Reputation: 825
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
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