Code

Opened 4 years ago

Closed 4 years ago

Last modified 4 years ago

#14065 closed (duplicate)

Admin: non-AutoField primary_key in child model breaks admin inlines (MultiValueDictKeyError)

Reported by: intgr Owned by: nobody
Component: Contrib apps Version: 1.2
Severity: Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

Let's say I have a parent-child model, where the child model has an explicit primary_key=True field. The parent admin page contains an inline for editing the child. Saving, or deleting the child, fails with a "MultiValueDictKeyError", because the primary key of the child is not being submitted. Full model&admin included below.

Environment:

Request Method: POST
Request URL: http://localhost:8001/admin/myapp/parent/1/
Django Version: 1.2.1
Python Version: 2.6.5
Installed Applications:
['django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.messages',
 'django.contrib.admin',
 'wtf.myapp']
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware')

Exception Type: MultiValueDictKeyError at /admin/myapp/parent/1/
Exception Value: "Key 'child_set-0-child_id' not found in
  <QueryDict: {u'child_set-0-name': [u'bar'], u'child_set-3-name': [u''], u'child_set-3-parent': [u'1'],
    u'child_set-MAX_NUM_FORMS': [u''], u'name': [u'foo'], u'_save': [u'Save'], u'child_set-__prefix__-name': [u''],
    u'child_set-__prefix__-parent': [u'1'], u'child_set-2-parent': [u'1'], u'child_set-2-name': [u''],
    u'child_set-0-parent': [u'1'], u'child_set-TOTAL_FORMS': [u'4'], u'child_set-1-parent': [u'1'],
    u'csrfmiddlewaretoken': [u'055944541276fbcb6a8a6d2fcb54968a'], u'child_set-INITIAL_FORMS': [u'1'],
    u'child_set-1-name': [u'']}>"

Traceback:
File "/usr/lib/python2.6/site-packages/django/core/handlers/base.py" in get_response
  100.                     response = callback(request, *callback_args, **callback_kwargs)
File "/usr/lib/python2.6/site-packages/django/contrib/admin/options.py" in wrapper
  239.                 return self.admin_site.admin_view(view)(*args, **kwargs)
File "/usr/lib/python2.6/site-packages/django/utils/decorators.py" in _wrapped_view
  76.                     response = view_func(request, *args, **kwargs)
File "/usr/lib/python2.6/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
  69.         response = view_func(request, *args, **kwargs)
File "/usr/lib/python2.6/site-packages/django/contrib/admin/sites.py" in inner
  190.             return view(request, *args, **kwargs)
File "/usr/lib/python2.6/site-packages/django/utils/decorators.py" in _wrapper
  21.             return decorator(bound_func)(*args, **kwargs)
File "/usr/lib/python2.6/site-packages/django/utils/decorators.py" in _wrapped_view
  76.                     response = view_func(request, *args, **kwargs)
File "/usr/lib/python2.6/site-packages/django/utils/decorators.py" in bound_func
  17.                 return func(self, *args2, **kwargs2)
File "/usr/lib/python2.6/site-packages/django/db/transaction.py" in _commit_on_success
  299.                     res = func(*args, **kw)
File "/usr/lib/python2.6/site-packages/django/contrib/admin/options.py" in change_view
  890.                                   queryset=inline.queryset(request))
File "/usr/lib/python2.6/site-packages/django/forms/models.py" in __init__
  698.                                                 queryset=qs)
File "/usr/lib/python2.6/site-packages/django/forms/models.py" in __init__
  423.         super(BaseModelFormSet, self).__init__(**defaults)
File "/usr/lib/python2.6/site-packages/django/forms/formsets.py" in __init__
  47.         self._construct_forms()
File "/usr/lib/python2.6/site-packages/django/forms/formsets.py" in _construct_forms
  97.             self.forms.append(self._construct_form(i))
File "/usr/lib/python2.6/site-packages/django/forms/models.py" in _construct_form
  711.         form = super(BaseInlineFormSet, self)._construct_form(i, **kwargs)
File "/usr/lib/python2.6/site-packages/django/forms/models.py" in _construct_form
  439.             pk = self.data[pk_key]
File "/usr/lib/python2.6/site-packages/django/utils/datastructures.py" in __getitem__
  233.             raise MultiValueDictKeyError("Key %r not found in %r" % (key, self))

model.py

from django.db import models

class Parent(models.Model):
    name = models.CharField(max_length=128)

class Child(models.Model):
    child_id = models.IntegerField(primary_key=True)
    # this also fails: id = models.IntegerField(primary_key=True, db_column='child_id')
    name = models.CharField(max_length=128)
    parent = models.ForeignKey(Parent)

admin.py

from wtf.myapp.models import *
from django.contrib import admin

class ChildInline(admin.TabularInline):
  model = Child
  fields = ['parent', 'name']

class ParentAdmin(admin.ModelAdmin):
  inlines = [ChildInline]
  fields = ['name']
admin.site.register(Parent, ParentAdmin)

Reproducing

  1. Create project and app, enable admin, add the above files and syncdb.
  2. Go to the admin interface and create a new Parent object
  3. Add a new child object to the parent
  4. Save
  5. Go back the the list
  6. Open the same parent object again
  7. Click save. Bam!

Attachments (0)

Change History (2)

comment:1 Changed 4 years ago by ramiro

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to duplicate
  • Status changed from new to closed

Seems like a duplicate of #12599. You are using a fields option in you Child Inline that excludes your IntegerField (and as such, manually controllable) PK, this is similar to the case attached to that ticker where the reporter was excluding his IntegerField PK by using the exclude option.

comment:2 Changed 4 years ago by intgr

  • Summary changed from Admin: Explicit primary_key in child model breaks admin inlines (MultiValueDictKeyError) to Admin: non-AutoField primary_key in child model breaks admin inlines (MultiValueDictKeyError)

You're right, AutoField is the solution. But since I'm not the first one to trip on this problem, I think you need a better error message here. I spent many hours trying to figure out what was wrong (I was using inspectdb to create the model and it doesn't recognize AutoField/serial columns in Postgres)

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.