【问题标题】:Django Form File Field disappears on form error表单错误时 Django 表单文件字段消失
【发布时间】:2011-12-15 03:31:51
【问题描述】:

问题来了,我有一个包含 File 字段的 Django 表单,即:

photo = forms.FileField(help_text="Please attach a photo", required=False)

如果表单验证通过,则文件字段已被正确绑定并保存。 问题是当用户填写所有表单但未验证时:所选文件的路径消失了

因此,如果用户没有意识到这一点,他/她修复其他字段错误并再次提交 - 这次没有照片。

以防万一,表单在视图中创建如下:

ProfileForm(request.POST or None, request.FILES or None)

HTML 是:

<div id="uniform-id_photo" class="uploader">
  <input id="id_photo" class="clearablefileinput" type="file" name="photo" size="19" style="opacity: 0;">
  <span class="filename" style="-moz-user-select: none;">No file selected</span>
  <span class="action" style="-moz-user-select: none;">Choose File</span>
</div>

以前有人遇到过同样的问题吗?对解决方案有任何想法吗? :)

谢谢!

【问题讨论】:

  • 如果您查看 django 管理员,每当您提交不正确的表单时,它都会重置文件路径。我想没有办法做到这一点,但为什么不在你的 html 中突出显示文件字段呢?
  • 是的,这可能是引起用户注意的最简单方法。谢谢!

标签: django file-upload django-forms validation


【解决方案1】:

不幸的是,这是浏览器强加的问题(实际上是一种安全功能),因此无法解决。浏览器不允许您为文件输入指定初始值,您无法解决此问题。

原因是,如果一个网站可以做到这一点,它会打开一个向量,允许任何网站通过猜测文件路径来窃取你计算机上的任何文件——他们可能只是在后台运行一个脚本来尝试将有趣的文件发布回服务器。

唯一的解决方法是无论表单是否有效,都将上传的文件实际保存在服务器上,然后当您将表单和错误返回给用户时,表明您已收到文件并且它们应该只填写删除该字段以替换它。

【讨论】:

  • 我明白了,有道理。感谢您的友好和详细的回答!
  • 另一种解决方法是执行 AJAX 请求来验证表单。
【解决方案2】:

我写了一些解决方案:

class CustomClearableFileInput(ClearableFileInput):

def render(self, name, value, attrs=None):
    if len(<YourModel>.objects.filter(id=self.form_instance_id))>0:
        file = <YourModel>.objects.get(id=self.form_instance_id).<yourField>
    else:
        file = ''
    substitutions = {
        'initial_text': self.initial_text,
        'input_text': self.input_text,
        'clear_template': '',
        'clear_checkbox_label': self.clear_checkbox_label,
    }
    template = '%(input)s'
    substitutions['input'] = super(ClearableFileInput, self).render(name, value, attrs)
    self.template_with_initial = ('<p class="file-upload">%s</p>'
                        % self.template_with_initial)
    self.template_with_clear = ('<span class="clearable-file-input">%s</span>'
                       % self.template_with_clear)

    if value and hasattr(value, "url"):
        template = self.template_with_initial
        substitutions['initial'] = format_html(self.url_markup_template,
                                               value.url,
                                               force_text(value))
        if not self.is_required:
            checkbox_name = self.clear_checkbox_name(name)
            checkbox_id = self.clear_checkbox_id(checkbox_name)
            substitutions['clear_checkbox_name'] = conditional_escape(checkbox_name)
            substitutions['clear_checkbox_id'] = conditional_escape(checkbox_id)
            substitutions['clear'] = CheckboxInput().render(checkbox_name, False, attrs={'id': checkbox_id})
            substitutions['clear_template'] = self.template_with_clear % substitutions
            url = '' if file == '' else file.url
    else:
        template = self.template_with_initial

        substitutions['initial'] = format_html(self.url_markup_template,
                                               url,
                                               force_text(file))
        if not self.is_required:
            checkbox_name = self.clear_checkbox_name(name)
            checkbox_id = self.clear_checkbox_id(checkbox_name)
            substitutions['clear_checkbox_name'] = conditional_escape(checkbox_name)
            substitutions['clear_checkbox_id'] = conditional_escape(checkbox_id)
            if fav == '':
                substitutions['clear'] = CheckboxInput().render(checkbox_name, False, attrs={'id': checkbox_id, 'disabled': 'disabled'})
            else:
                substitutions['clear'] = CheckboxInput().render(checkbox_name, False, attrs={'id': checkbox_id})
            substitutions['clear_template'] = self.template_with_clear % substitutions



    return mark_safe(template % substitutions)

然后在你的表格中你必须写:

class <YourModel>Form(ModelForm):
    class Meta:
        model = <YourModel>
        fields = '__all__'
        widgets= {'<YourField>': CustomClearableFileInput}

    def __init__(self, *args, **kwargs):
        super(OperatorSettingsForm, self).__init__(*args, **kwargs)
        self.fields['<YourField>'].widget.form_instance_id = self.instance.id

它对我有用。我想你也不会有问题的:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-11
    • 2012-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-02
    • 2021-03-31
    相关资源
    最近更新 更多