带有 ImageFields 的 ModelForm,如果验证错误则无法正确清除

发布于 2024-12-03 00:24:59 字数 1086 浏览 0 评论 0原文

首先是代码。 ModelForm(im1 和 im2 是 models.ImageField):

class TestForm(forms.ModelForm):
    checkme = forms.BooleanField(required=True)

    class Meta:
        model = UserProfile
        fields = ('im1', 'im2')

视图:

def test(request):
    profile = request.user.get_profile()
    form = TestForm(instance=profile)
    if request.method == "POST":
        form = TestForm(request.POST, request.FILES, instance=profile)
        if form.is_valid():
            form.save()
    return render(request, 'test.html', {'form':form})

模板:

<html>
<head>
<title>Test</title>
</head>
<body>
<form method="post" enctype="multipart/form-data">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="submit" />
</form>
</body>
</html>

问题:

如果 im1 包含有效图像,并且我选中旁边的清除复选框,但不选中 checkme 并提交,则表单会返回错误提示需要 checkme。尽管表单返回时出现错误,但看起来好像 im1 已被清除。实际上,它没有,因为如果我重新加载表单,im1 将显示备份及其文件并清除复选框。

我的问题是如何解决这个问题?这是我正在做的事情还是与 django 有关?

First the code.
The ModelForm (im1 and im2 are models.ImageField):

class TestForm(forms.ModelForm):
    checkme = forms.BooleanField(required=True)

    class Meta:
        model = UserProfile
        fields = ('im1', 'im2')

The view:

def test(request):
    profile = request.user.get_profile()
    form = TestForm(instance=profile)
    if request.method == "POST":
        form = TestForm(request.POST, request.FILES, instance=profile)
        if form.is_valid():
            form.save()
    return render(request, 'test.html', {'form':form})

The template:

<html>
<head>
<title>Test</title>
</head>
<body>
<form method="post" enctype="multipart/form-data">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="submit" />
</form>
</body>
</html>

The problems:

If im1 contains a valid image, and I check the clear checkbox next to it but don't check checkme and submit, the form comes back with an error saying that checkme is required. Although the form returns with the error, it appears as if im1 has been cleared. In reality it has not because if I reload the form im1 shows back up with its file and clear checkbox.

My question is how can I fix this? Is it something I am doing or is this something to do with django?

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

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

发布评论

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

评论(1

一抹苦笑 2024-12-10 00:24:59

Django 的行为完全符合它应该做的。

如果请求是 POST 请求,则您的表单将绑定到 request.POSTrequest.FILES 中的数据。 instance=profile 只是告诉表单,如果所有验证通过,要保存到哪个特定对象。即使您的表单无效,它仍然会绑定到带有已清除图像的数据,这就是您传递给 render() 的内容。

首先,如果请求方法是 POST,您不应该创建第一个绑定表单:

def test(request):
    profile = request.user.get_profile()
    if request.method == "POST":
        form = TestForm(request.POST, request.FILES, instance=profile)
        if form.is_valid():
            form.save()
    else:
        form = TestForm(instance=profile)
    return render(request, 'test.html', {'form':form})

其次,如果用户确实想要删除图像但只是错过了另一个复选框,为什么您希望用户执行两次相同的操作?

如果你真的需要 Django 以这种方式行事,我会做以下两件事之一。从 UserProfile 实例创建绑定表单,并将无效表单和新创建的表单传递给模板,并使用无效表单显示错误,使用另一个表单显示表单的其余部分:

def test(request):
    profile = request.user.get_profile()
    if request.method == "POST":
        errors_form = TestForm(request.POST, request.FILES, instance=profile)
        if errors_form.is_valid():
            errors_form.save()
            form = errors_form
        else:
            form = TestForm(instance=profile)
            return render(request, 'test.html', {'form':form, 'errors_form': errors_form})
    else:
        form = TestForm(instance=profile)
    return render(request, 'test.html', {'form':form})

或者我会做同样的事情,但将无效表单中的错误保存到新创建的表单中,这样您就不会到处都是 renders()

def test(request):
    profile = request.user.get_profile()
    if request.method == "POST":
        errors_form = TestForm(request.POST, request.FILES, instance=profile)
        if errors_form.is_valid():
            errors_form.save()
            form = errors_form
        else:
            form = TestForm(instance=profile)
            #this is left up to you to implement, but you'd do something like
            #form.errors = errors_form.errors
            #and also iterate through every form attribute.errors and assign it to
            #errors_form attribute.errors etc...
    else:
        form = TestForm(instance=profile)
    return render(request, 'test.html', {'form':form})

两者都不是很好优雅的解决方案,我不肯定第二个由于我不完全熟悉 Django Forms 实现,因此甚至可以按预期工作,无需更多修改。

我不认为这样做值得。正如我之前所说,你只是在为你的用户创造更多的工作......

Django is acting exactly as it should.

If the request is a POST request, then your form is bound to the data from request.POST and request.FILES. instance=profile is simply telling the form what particular object to save to if all validation passes. Even if your form isn't valid, it's still bound to the data with the cleared image, and that's what you're passing to render().

Firstly, you shouldn't be creating the first bound form if the request method is POST:

def test(request):
    profile = request.user.get_profile()
    if request.method == "POST":
        form = TestForm(request.POST, request.FILES, instance=profile)
        if form.is_valid():
            form.save()
    else:
        form = TestForm(instance=profile)
    return render(request, 'test.html', {'form':form})

Secondly, why do you want your user to do the same exact action twice if they did indeed want to delete an image but simply missed another checkbox?

If you really need Django to act this way, I would do one of two things. Either create a bound form from an instance of UserProfile and pass both the non-valid form and the newly created form to the template and use the non-valid form for displaying the errors and the other one for displaying the rest of the form:

def test(request):
    profile = request.user.get_profile()
    if request.method == "POST":
        errors_form = TestForm(request.POST, request.FILES, instance=profile)
        if errors_form.is_valid():
            errors_form.save()
            form = errors_form
        else:
            form = TestForm(instance=profile)
            return render(request, 'test.html', {'form':form, 'errors_form': errors_form})
    else:
        form = TestForm(instance=profile)
    return render(request, 'test.html', {'form':form})

OR I'd do the same thing but save the errors from the non-valid form to the newly created form so you don't end up with renders() all over the place:

def test(request):
    profile = request.user.get_profile()
    if request.method == "POST":
        errors_form = TestForm(request.POST, request.FILES, instance=profile)
        if errors_form.is_valid():
            errors_form.save()
            form = errors_form
        else:
            form = TestForm(instance=profile)
            #this is left up to you to implement, but you'd do something like
            #form.errors = errors_form.errors
            #and also iterate through every form attribute.errors and assign it to
            #errors_form attribute.errors etc...
    else:
        form = TestForm(instance=profile)
    return render(request, 'test.html', {'form':form})

Both aren't very elegant solutions and I'm not positive the second one will even work as expected without some more hacks since I'm not completely familiar with the Django Forms implementation.

I don't see that doing this is worth it. As I stated before, you're just creating more work for your user...

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