【问题标题】:Extending a form field to add new validations扩展表单字段以添加新的验证
【发布时间】:2010-04-28 23:14:52
【问题描述】:

我编写了一个应用程序,它使用表单收集信息,然后通过电子邮件发送。其中许多表单都有一个用于将文件附加到电子邮件的文件字段。我想验证两件事,文件的大小(以确保我们的邮件服务器接受电子邮件。我还想检查文件扩展名,以阻止附加对我们的用户不可用的文件类型。

(这是我要扩展的python类)

class FileField(Field):
    widget = FileInput
    default_error_messages = {
        'invalid': _(u"No file was submitted. Check the encoding type on the form."),
        'missing': _(u"No file was submitted."),
        'empty': _(u"The submitted file is empty."),
        'max_length': _(u'Ensure this filename has at most %(max)d characters (it has %(length)d).'),
    }

    def __init__(self, *args, **kwargs):
        self.max_length = kwargs.pop('max_length', None)
        super(FileField, self).__init__(*args, **kwargs)

    def clean(self, data, initial=None):
        super(FileField, self).clean(initial or data)
        if not self.required and data in EMPTY_VALUES:
            return None
        elif not data and initial:
            return initial

        # UploadedFile objects should have name and size attributes.
        try:
            file_name = data.name
            file_size = data.size
        except AttributeError:
            raise ValidationError(self.error_messages['invalid'])

        if self.max_length is not None and len(file_name) > self.max_length:
            error_values =  {'max': self.max_length, 'length': len(file_name)}
            raise ValidationError(self.error_messages['max_length'] % error_values)
        if not file_name:
            raise ValidationError(self.error_messages['invalid'])
        if not file_size:
            raise ValidationError(self.error_messages['empty'])
    return data

【问题讨论】:

    标签: python django oop django-forms


    【解决方案1】:

    只需重载“clean”方法:

    def clean(self, data, initial=None):
        try:
            if data.size > somesize:
                raise ValidationError('File is too big')
    
            (junk, ext) = os.path.splitext(data.name)
            if not ext in ('.jpg', '.gif', '.png'):
                raise ValidationError('Invalid file type')
    
        except AttributeError:
            raise ValidationError(self.error_messages['invalid'])
    
        return FileField.clean(self, data, initial)
    

    【讨论】:

    • 我最终遵循了您的方法。感谢您的帮助!
    【解决方案2】:

    在我看来,子类化实际的字段类需要付出很多努力。简单地扩展您的表单类应该更容易。您可以添加一个“清理”文件字段的方法。

    例如:

    class MyForm(forms.Form):
      attachment = forms.FileField(...)
    
      def clean_attachment(self):
        data = self.cleaned_data['attachment'] // UploadedFile object
        exts = ['jpg', 'png'] // allowed extensions
    
        // 1. check file size
        if data.size > x:
          raise forms.ValidationError("file to big")
    
        // 2. check file extension
        file_extension = data.name.split('.')[1] // simple method
    
        if file_extension not in exts:
          raise forms.ValidationError("Wrong file type")
    
        return data
    

    这只是一个基本的例子,还有一些粗糙的地方。但是您可以使用此示例并对其进行改进,直到找到适合您的版本。

    推荐阅读:

    Django Doc - Cleaning a specific field

    Django Doc - UploadedFile class

    Django Doc - File class

    【讨论】:

    • 感谢您的回答。我最终使用您的方法进行扩展验证。我选择实现一个子类,因为要对大约 20 个表单进行此验证。您的元方法将有助于验证其他一些字段。
    • 但请注意,这仅适用于包含一个点的文件名。带有多个点的文件名将破坏验证。而是使用这样的东西:(shortname, extension) = os.path.splitext(filename).
    【解决方案3】:

    这就是我最终做的:

    在我应用的设置文件中:

    exts = ['doc', 'docx', 'pdf', 'jpg', 'png', 'xls', 'xlsx', '.xlsm', '.xlsb']
    max_email_attach_size = 10485760 #10MB written in bytes
    

    在一个名为 formfunctions 的新文件中:

    from django import forms
    from django.forms.util import ErrorList, ValidationError
    from app.settings import exts, max_email_attach_size
    
    
    class SizedFileField(forms.FileField):
    
        def clean(self, data, initial=None):
    
            if not data in (None, ''):
    
                try:
                    if data.size > max_email_attach_size:
                        raise ValidationError("The file is too big")
    
                    file_extension = data.name.split('.')[1]
                    if file_extension not in exts:
                        raise ValidationError("Invalid File Type")
    
                except AttributeError:
                    raise ValidationError(self.error_messages['invalid'])
    
            return forms.FileField.clean(self, data, initial)
    

    在我的表单文件中:

    from formfunctions import SizedFileField
    

    表单文件中的示例类:

    class ExampleClass(forms.Form):
        Email_Body = forms.CharField(widget=forms.Textarea, required=False)
        Todays_Date = forms.CharField()
        Attachment = SizedFileField(required=False)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-19
      • 1970-01-01
      • 2013-12-11
      • 1970-01-01
      • 2021-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多