Question

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?

Was it helpful?

Solution

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top