﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
34700	ValidatedFileField	Reza Shakeri	nobody	"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"")

}}}
"	New feature	closed	File uploads/storage	4.2	Normal	duplicate	file, file validator, file validation, validator, file		Unreviewed	0	0	0	0	0	0
