#34700 closed New feature (duplicate)

ValidatedFileField

Reported by: Reza Shakeri Owned by: nobody
Component: File uploads/storage Version: 4.2
Severity: Normal Keywords: file, file validator, file validation, validator, file
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Hi

I want to add a valid file field (ValidatedFileField) to Django that checks the size, MIME and extension of files as well as their validity using the Python (mimetypes : https://docs.python.org/3/library/mimetypes.html) Built-in Library And the same is tested, ValidatedFileField makes files more reliable

class ValidatedFileField(FileField):
    """
    :return: If everything is OK, it will return None, otherwise it will
        return a ValidationError.
    """

    def __init__(self, *args, **kwargs):
        """
        :type acceptable_mimes: list
        :param acceptable_mimes: The mimes you want the file to be checked
            based on, example: image/png
        :type max_upload_file_size: int, optional
        :param max_upload_file_size: If you want the file size to be checked,
            the file size must be in bytes,
            example: file_size=1048576 (1MB), defaults to 0, optional
        :raises ValueError: If the mime list is empty, raised a value error
        :raises ValueError: If the library you entered is not supported,
            raised a value error, Supported library: filetype, mimetypes,
            pure_magic, python_magic
        :raises ValidationError: if file not valid
        """
        self.max_upload_file_size: int = kwargs.pop("max_upload_file_size", None)
        self.acceptable_mimes: list = kwargs.pop("acceptable_mimes", None)
        self.acceptable_extensions: list = kwargs.pop("acceptable_extensions", None)

        if acceptable_mimes is None:
            raise ValueError("acceptable mimes are empty")

        if acceptable_mimes is not None:
            if len(acceptable_mimes) == 1:
                return False
            group = groupby(acceptable_mimes)
            mimes_is_equal = next(group, True) and not next(group, False)
            if mimes_is_equal:
                raise ValueError("acceptable mimes are equal")


        super().__init__(*args, **kwargs)

    def deconstruct(self):
        name, path, args, kwargs = super().deconstruct()
        kwargs["acceptable_mimes"] = self.acceptable_mimes
        kwargs["acceptable_extensions"] = self.acceptable_extensions
        kwargs["max_upload_file_size"] = self.max_upload_file_size
        return name, path, args, kwargs

    def clean(self, *args, **kwargs):
        data = super().clean(*args, **kwargs)
        current_file = data.file
        file_size = data.size
        file_path = TemporaryUploadedFile.temporary_file_path(current_file)
        if self.acceptable_mimes is not None:
            try:
                content_type = current_file.content_type
            except AttributeError:
                content_type = None
            file_mime = guess_type(file_path)[0]
            if content_type is not None and content_type not in self.acceptable_mimes:
                raise ValidationError("file mime is not valid")
            if file_mime is not None and file_mime not in self.acceptable_mimes:
                raise ValidationError("file mime is not valid")
        if self.acceptable_extensions is not None:
            file_extension = Path(file_path).suffix
            if file_extension not in self.acceptable_extensions:
                raise ValidationError("file extentions is not valid")
        if self.max_upload_file_size is not None:
            file_size = os.path.getsize(file_path)
            if (
                self.max_upload_file_size is not None
                and file_size > self.max_upload_file_size
            ):
                raise ValidationError("file size is not valid")

Change History (2)

comment:1 by Abdulla Dlshad, 17 months ago

The proposed feature looks promising. However, it seems like the file field has too much responsibility which I am not sure if it would best practice for a django file field. Different validation classes could be used for each one of the validations.
In addition, I don't know why the use of file type checking library should be an option for the developer to use as long as they could all give you the desired output.

comment:2 by Mariusz Felisiak, 17 months ago

Resolution: duplicate
Status: newclosed

Another duplicate of #33942 and #34263.

Note: See TracTickets for help on using tickets.
Back to Top