Opened 11 years ago

Closed 11 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

Description

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:

views.py

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)
    else:
        formset = FormSet()

    csrf = get_token(request)

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

models.py

from django.db import models

class App(models.Model):
    pass

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

Change History (3)

comment:1 by Aymeric Augustin, 11 years ago

Could you provide the full traceback please?

comment:2 by Robin, 11 years ago

Sure.

Environment:


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

Django Version: 1.6
Python Version: 2.7.6
Installed Applications:
('django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'app')
Installed Middleware:
('django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware')


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 :     

Traceback:
File "/home/robin/work/d16/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  114.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/robin/work/d16/toast/toast/views.py" in home
  28.     s = Template(t).render(Context(c))
File "/home/robin/work/d16/lib/python2.7/site-packages/django/template/base.py" in render
  140.             return self._render(context)
File "/home/robin/work/d16/lib/python2.7/site-packages/django/template/base.py" in _render
  134.         return self.nodelist.render(context)
File "/home/robin/work/d16/lib/python2.7/site-packages/django/template/base.py" in render
  840.                 bit = self.render_node(node, context)
File "/home/robin/work/d16/lib/python2.7/site-packages/django/template/debug.py" in render_node
  78.             return node.render(context)
File "/home/robin/work/d16/lib/python2.7/site-packages/django/template/debug.py" in render
  91.             output = force_text(output)
File "/home/robin/work/d16/lib/python2.7/site-packages/django/utils/encoding.py" in force_text
  100.                 s = s.__unicode__()
File "/home/robin/work/d16/lib/python2.7/site-packages/django/forms/formsets.py" in __str__
  61.         return self.as_table()
File "/home/robin/work/d16/lib/python2.7/site-packages/django/forms/formsets.py" 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/formsets.py" in __iter__
  65.         return iter(self.forms)
File "/home/robin/work/d16/lib/python2.7/site-packages/django/utils/functional.py" in __get__
  49.         res = instance.__dict__[self.func.__name__] = self.func(instance)
File "/home/robin/work/d16/lib/python2.7/site-packages/django/forms/formsets.py" 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/models.py" in _construct_form
  843.             form.data[form.add_prefix(self._pk_field.name)] = None
File "/home/robin/work/d16/lib/python2.7/site-packages/django/http/request.py" in __setitem__
  318.         self._assert_mutable()
File "/home/robin/work/d16/lib/python2.7/site-packages/django/http/request.py" in _assert_mutable
  315.             raise AttributeError("This QueryDict instance is immutable")

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

comment:3 by Aymeric Augustin, 11 years ago

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