Django 表单文件字段因表单错误而消失

发布于 2024-12-12 01:22:07 字数 822 浏览 0 评论 0原文

问题是,我有一个包含文件字段的 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>

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

谢谢!

Here is the problem, I have a Django Form containing a File field, namely:

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

If the form validates, the File field is bounded and saved correctly. The problem is when the user fills all the form and it doesn't validate: the path of the selected file disappear.

So, if the user doesn't realize about this, he/she fix the other fields errors and submit again - with no photo this time.

Just in case, the form is created in the view like this:

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

and the HTML is:

<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>

Has anyone had the same problem before? Any thoughts towards a solution? :)

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

岁月如刀 2024-12-19 01:22:07

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

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

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

Unfortunately, this is a problem (really a security feature) imposed by browsers, and is not solvable, as such. Browsers will not let you specify an initial value for file inputs, and there's nothing that you will be able to do to work around that.

The reason is that if a website could do this, it would open up a vector that would allow any website to steal any file on your computer by guessing file paths--they could just have a script running in the background that tried to post interesting files back to the server.

The only workaround is to actually save the uploaded file on the server regardless of whether the form validates, and then when you render the form and errors back to the user, indicate that you have received a file and that they should only fill out that field to replace it.

天涯沦落人 2024-12-19 01:22:07

我写了一些解决方案:

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

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

I write some solution:

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)

And then in your form you must write:

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

It works for me. I think you will have no problem too :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文