Opened 4 years ago

Closed 4 years ago

#21955 closed Bug (invalid)

Formset save_as_new=True causes "This QueryDict instance is immutable" error

Reported by: Robin Owned by: nobody
Component: Forms Version: 1.6
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


Basically if you post a properly setup inline formset with save_as_new=True argument:

FormSet = inlineformset_factory(Model, SubModel)
formset = FormSet(request.POST, save_as_new=True)

You will get

AttributeError at /
This QueryDict instance is immutable

Some demo code below:

from django.forms.models import inlineformset_factory
from django.middleware.csrf import get_token
from django.http import HttpResponse
from django.template.base import Template, Context

from app.models import App, SubApp

def home(request):
    FormSet = inlineformset_factory(App, SubApp)
    if request.method == 'POST':
        formset = FormSet(request.POST, save_as_new=True)
        formset = FormSet()

    csrf = get_token(request)

    t = '''
        <form method="POST">
            {{ formset }}
            <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf }}" />
            <input type="submit" />
    c = {
        'formset': formset,
        'csrf': csrf,
    s = Template(t).render(Context(c))
    return HttpResponse(s)

from django.db import models

class App(models.Model):

class SubApp(models.Model):
    app = models.ForeignKey(App)

Change History (3)

comment:1 Changed 4 years ago by Aymeric Augustin

Could you provide the full traceback please?

comment:2 Changed 4 years ago by Robin



Request Method: POST
Request URL: http://localhost:8001/

Django Version: 1.6
Python Version: 2.7.6
Installed Applications:
Installed Middleware:

Template error:
In template <unknown source>, error at line 3
   This QueryDict instance is immutable
   1 : 

   2 :         <form method="POST">

   3 :              {{ formset }} 

   4 :             <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf }}" />

   5 :             <input type="submit" />

   6 :         </form>

   7 :     

File "/home/robin/work/d16/lib/python2.7/site-packages/django/core/handlers/" in get_response
  114.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/robin/work/d16/toast/toast/" in home
  28.     s = Template(t).render(Context(c))
File "/home/robin/work/d16/lib/python2.7/site-packages/django/template/" in render
  140.             return self._render(context)
File "/home/robin/work/d16/lib/python2.7/site-packages/django/template/" in _render
  134.         return self.nodelist.render(context)
File "/home/robin/work/d16/lib/python2.7/site-packages/django/template/" in render
  840.                 bit = self.render_node(node, context)
File "/home/robin/work/d16/lib/python2.7/site-packages/django/template/" in render_node
  78.             return node.render(context)
File "/home/robin/work/d16/lib/python2.7/site-packages/django/template/" in render
  91.             output = force_text(output)
File "/home/robin/work/d16/lib/python2.7/site-packages/django/utils/" in force_text
  100.                 s = s.__unicode__()
File "/home/robin/work/d16/lib/python2.7/site-packages/django/forms/" in __str__
  61.         return self.as_table()
File "/home/robin/work/d16/lib/python2.7/site-packages/django/forms/" in as_table
  383.         forms = ' '.join([form.as_table() for form in self])
File "/home/robin/work/d16/lib/python2.7/site-packages/django/forms/" in __iter__
  65.         return iter(self.forms)
File "/home/robin/work/d16/lib/python2.7/site-packages/django/utils/" in __get__
  49.         res = instance.__dict__[self.func.__name__] = self.func(instance)
File "/home/robin/work/d16/lib/python2.7/site-packages/django/forms/" in forms
  133.         forms = [self._construct_form(i) for i in xrange(self.total_form_count())]
File "/home/robin/work/d16/lib/python2.7/site-packages/django/forms/" in _construct_form
  843.   [form.add_prefix(] = None
File "/home/robin/work/d16/lib/python2.7/site-packages/django/http/" in __setitem__
  318.         self._assert_mutable()
File "/home/robin/work/d16/lib/python2.7/site-packages/django/http/" in _assert_mutable
  315.             raise AttributeError("This QueryDict instance is immutable")

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

comment:3 Changed 4 years ago by Aymeric Augustin

Resolution: invalid
Status: newclosed

I'm not sure this is legal. Django's tests pass an instance and in that case save_as_new appears to work. The docs also show an example with an instance parameter.

Anyway, since save_as_new isn't documented, you're in private API territory here. If you have a patch for this we may take a look, otherwise we're just going to say that the public API works.

Note: See TracTickets for help on using tickets.
Back to Top