示例#1
0
def handle_uploaded_file(f: File,
                         path: Optional[List[str]] = None,
                         name: Optional[str] = None,
                         max_length: Optional[int] = None) -> str:
    """Handle an uploaded file by a form and return the complete file's path
    path has to be iterable
    """
    def get_name(file: File) -> str:
        if hasattr(file, 'name'):
            name = file.name
        elif hasattr(file, '_name'):
            name = file._name
        else:
            name = 'file_{:08x}'.format(randint(0, MAXINT))

        if name.rpartition('.')[2] not in settings.ALLOWED_EXTENSIONS:
            name = f'{name}.txt'

        return name

    dir_path_length = 1  # For the final '/'

    if not hasattr(path, '__iter__'):  # TODO: path is None  (or add support for only one string)
        relative_dir_path = 'upload'
        dir_path = join(settings.MEDIA_ROOT, relative_dir_path)
        dir_path_length += len(relative_dir_path)
    else:
        relative_dir_path = join(*path)
        dir_path = join(settings.MEDIA_ROOT, *path)

        # The storage uses '/' even on Windows.
        dir_path_length += len('/'.join(relative_dir_path))

    if not name:
        name = get_name(f)

    if max_length:
        max_length -= dir_path_length

        if max_length <= 0:
            raise ValueError('The max length is too small.')

    final_path = FileCreator(dir_path=dir_path, name=name, max_length=max_length).create()

    with open(final_path, 'wb', 0o755) as destination:
        for chunk in f.chunks():
            destination.write(chunk)

    return join(relative_dir_path, basename(final_path))