chris
chris

Reputation: 825

Getting "This QueryDict instance is immutable" on one Django view but not another

I have two views, one that is working fine when I try to add to the POST data when a form is not valid, another that gives me a "This QueryDict instance is immutable" error when trying to do the same thing. I know these views are too similar to exist in the first place and plan on combining them... but would like to first understand what is the difference that makes one of them fail.

This view works fine:

@login_required
def url_parse(request):
    cu = request.user
    if request.method == 'POST':
        form = UrlBragForm(request.POST, request.FILES)
        if form.is_valid():
            t = handle_image_upload(form.cleaned_data['image'],cu.pk,'url')
            if t:
                b = Brag()
                b.user = cu
                b.image = t
                b.url = form.cleaned_data['url']
                b.description = form.cleaned_data['brag']
                b.active = True
                b.timestamp = time.time()
                b.save()
                tags = parse_tags(form.cleaned_data['brag'])
                if tags:
                    for tg in tags:
                        b.tags.add(tg)
            else:
                errors = form._errors.setdefault("image", ErrorList())
                errors.append(u"There was an issue with your image.  Please try again.")
        else:
            clean = cleanMessage(request.POST['brag'])
            if clean != 'is_clean':
                request.POST['brag'] = clean
    else:
        form = UrlBragForm()
    return render_to_response('brag/url_brag.html', {'form':form,}, context_instance=RequestContext(request))

But this view gives me a "This QueryDict instance is immutable" when trying to fill the request.POST['brag'] with the 'clean' data when view is not valid:

@login_required
def brag_add_image(request):
    cu = request.user
    if request.method == 'POST':
        form = ImageAddBragForm(request.POST, request.FILES)
        if form.is_valid():
            t = handle_image_upload(form.cleaned_data['image'],cu.pk,'url')
            if t:
                b = Brag()
                b.user = cu
                b.image = t
                b.description = form.cleaned_data['brag']
                b.active = True
                b.timestamp = time.time()
                b.save()
                b.url = 'http://%s%s' % (Site.objects.get_current().domain, reverse('image_display', args=(b.pk,)))
                b.save()
                tags = parse_tags(form.cleaned_data['brag'])
                if tags:
                    for tg in tags:
                        b.tags.add(tg)
            else:
                errors = form._errors.setdefault("image", ErrorList())
                errors.append(u"There was an issue with your image.  Please try again.")
        else:
            clean = cleanMessage(request.POST['brag'])
            if clean != 'is_clean':
                request.POST['brag'] = clean
    else:
        form = ImageAddBragForm()
    return render_to_response('brag/image_brag_add.html', {'form':form,}, context_instance=RequestContext(request))

Here is the traceback that was asked for:

Traceback:
File "site/src/django/django/core/handlers/base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "site/src/django/django/contrib/auth/decorators.py" in _wrapped_view
  20.                 return view_func(request, *args, **kwargs)
File "site/brag/views.py" in brag_add_image
  241.                 request.POST['brag'] = clean
File "site/src/django/django/http/__init__.py" in __setitem__
  439.         self._assert_mutable()
File "site/src/django/django/http/__init__.py" in _assert_mutable
  436.             raise AttributeError("This QueryDict instance is immutable")

Exception Type: AttributeError at /brag/brag_add_image/
Exception Value: This QueryDict instance is immutable

Upvotes: 4

Views: 13251

Answers (1)

chris
chris

Reputation: 825

Figured it out. It is because of the way I was calling the form in the template. If you change your enctype to multipart you no longer get the error. This in no way is a fix, and you should look at doing this in your form class not a view. But I wanted to figure out why it worked one way and not another.

<form action="." method="post" class="genForm" enctype="multipart/form-data">

vs

<form action="." method="post" class="genForm">

This seems like it could be a bug in Django (why not enforce in both cases?)

Since there seems to be some confusion with this answer I here is a simpler example that shows the same out come:

View :

def testit(request):
    if request.method == "POST":
        form = testForm(request.POST, request.FILES)
        clean = 'Going to stuff post data with this string'
        if form.is_valid():
            print 'valid'
            request.POST['testOne'] = clean
        else:
            print 'not valid'
            request.POST['testOne'] = clean
    else:
        form = testForm()
    return render_to_response('brag_board/test.html', {'form':form}, context_instance=RequestContext(request))

Form:

class testForm(forms.Form):
    testOne = forms.CharField(required=True)
    testTwo = forms.CharField(required=True)

Template that gives a error:

<!DOCTYPE html>
<html>
<head>
    <title>test</title>
</head>
<body>

<form action="." method="post" class="genForm">
{{ form }}
{% csrf_token %}
<button type="submit" name="action" value="addnewsletter">test</button>
</form>

</body>
</html>

Template that does not give an error:

<!DOCTYPE html>
<html>
<head>
    <title>test</title>
</head>
<body>

<form action="." method="post" class="genForm" enctype="multipart/form-data">
{{ form }}
{% csrf_token %}
<button type="submit" name="action" value="addnewsletter">test</button>
</form>

</body>
</html>

Upvotes: 4

Related Questions