【问题标题】:Django form validation, clean(), and file uploadDjango 表单验证、clean() 和文件上传
【发布时间】:2011-06-29 11:40:15
【问题描述】:

有人能告诉我上传的文件何时实际写入 FileField 中“upload_to”返回的位置,特别是关于字段、模型和表单验证和清理的顺序吗?

现在我的模型上有一个“干净”的方法,它假设上传的文件已经到位,所以它可以对其进行一些验证。看起来该文件尚未保存,可能只是保存在临时位置或内存中。如果是这种情况,如果我需要执行一些外部进程/程序来验证文件,我该如何“打开”它或找到它的路径?

谢谢,

伊恩

【问题讨论】:

    标签: django validation upload


    【解决方案1】:

    表单清理与实际保存文件或保存任何其他数据无关。在您运行模型实例的save() 方法之前,文件不会保存(请注意,如果您使用ModelName.objects.create(),则会自动为您调用此save() 方法)。

    绑定的表单将包含一个打开的File 对象,因此您应该能够直接对该对象进行任何验证。例如:

    form = MyForm(request.POST, request.FILES)
    if form.is_valid():
        file_object = form.cleaned_data['myFile']
        #run any validation on the file_object, or define a clean_myFile() method 
        #  that will be run automatically when you call form.is_valid()
    
        model_inst = MyModel('my_file' = file_object,
                         #assign other attributes here....
                         )
        model_inst.save() #file is saved to disk here
    

    【讨论】:

    • 有什么方法可以在模型验证而不是表单验证中做到这一点?
    【解决方案2】:

    你需要做什么?如果您的验证将在没有临时文件的情况下工作,您可以通过在文件字段返回的内容上调用 read() 来访问数据。

    def clean_field(self):
        _file = self.cleaned_data.get('filefield')
        contents = _file.read()
    

    如果你确实需要它在磁盘上,你知道从这里到哪里去 :) 把它写到一个临时位置并在它上面做一些魔法!

    【讨论】:

    • 我希望这个验证进入 Model.clean() 方法,而不是表单验证,但似乎这是不可能的,是对吗?上传的文件验证只能在表单级别发生,就像你所说的那样。
    • 等等,没关系,我记得读过一篇关于如何做到这一点的 SO 帖子……让我去挖掘。抱歉找不到。如果模型已经保存,您可以访问self.field.file.read()
    【解决方案3】:

    或将其写为自定义表单字段。这是我使用“诱变剂”库验证 MP3 文件的基本思路。

    注意事项:

    • 首先检查文件大小,如果大小正确,则写入 tmp 位置。
    • 将文件写入 SETTINGS 中指定的临时位置检查其 MP3,然后将其删除。

    代码:

    from django import forms
    
    import os
    from mutagen.mp3 import MP3, HeaderNotFoundError, InvalidMPEGHeader
    
    from django.conf import settings
    
    class MP3FileField(forms.FileField):
    
        def clean(self, *args, **kwargs):
            super(MP3FileField, self).clean(*args, **kwargs)
            tmp_file = args[0]
    
            if tmp_file.size > 6600000:
                raise forms.ValidationError("File is too large.")
    
            file_path = getattr(settings,'FILE_UPLOAD_TEMP_DIR')+'/'+tmp_file.name
    
            destination = open(file_path, 'wb+')
            for chunk in tmp_file.chunks():
                destination.write(chunk)
            destination.close()
    
            try:
                audio = MP3(file_path)
                if audio.info.length > 300:
                    os.remove(file_path)
                    raise forms.ValidationError("MP3 is too long.")
    
            except (HeaderNotFoundError, InvalidMPEGHeader):
                os.remove(file_path)
                raise forms.ValidationError("File is not valid MP3 CBR/VBR format.")
            os.remove(file_path)
            return args
    

    【讨论】:

      猜你喜欢
      • 2012-09-08
      • 1970-01-01
      • 2011-01-31
      • 2015-10-31
      • 1970-01-01
      • 2011-07-07
      • 2012-05-09
      • 2019-05-13
      • 2012-07-29
      相关资源
      最近更新 更多