Opened 14 years ago

Closed 13 years ago

Last modified 11 years ago

#12235 closed Uncategorized (fixed)

MultiValueDictKeyError when editing Inline objects

Reported by: bruce@… Owned by: nobody
Component: contrib.admin Version: 1.2
Severity: Normal Keywords:
Cc: wgordonw1@… Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Alex Gaynor)

the attached simple model (Book and Author), using a custom UUID type as described here: http://www.gordontillman.info/computers/41-django/94-django-uuidfield-problem

If you add a book with an author, and then try to edit the authors (add a second one, edit the name, etc), you will generate this error:

MultiValueDictKeyError at /admin/gamedata/book/7432e312-d39b-11de-913b-00188b8e3ea8/

Key 'author_set-0-id' not found in <QueryDict: {u'_save': [u'Save'], u'author_set-TOTAL_FORMS': [u'5'], u'author_set-0-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'title': [u'book1'], u'author_set-0-name': [u'author1'], u'author_set-3-name': [u''], u'author_set-2-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'author_set-INITIAL_FORMS': [u'2'], u'author_set-4-name': [u''], u'author_set-2-name': [u'asdasdasd'], u'author_set-3-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'author_set-1-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'author_set-4-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'author_set-1-name': [u'authro2']}>

Traceback:
File "/usr/lib64/python2.6/site-packages/django/core/handlers/base.py" in get_response
  92.                 response = callback(request, *callback_args, **callback_kwargs)
File "/usr/lib64/python2.6/site-packages/django/contrib/admin/options.py" in wrapper
  226.                 return self.admin_site.admin_view(view)(*args, **kwargs)
File "/usr/lib64/python2.6/site-packages/django/utils/decorators.py" in __call__
  23.         return self.decorator(self.func)(*args, **kwargs)
File "/usr/lib64/python2.6/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
  70.         response = view_func(request, *args, **kwargs)
File "/usr/lib64/python2.6/site-packages/django/contrib/admin/sites.py" in inner
  186.             return view(request, *args, **kwargs)
File "/usr/lib64/python2.6/site-packages/django/db/transaction.py" in _commit_on_success
  240.                 res = func(*args, **kw)
File "/usr/lib64/python2.6/site-packages/django/contrib/admin/options.py" in change_view
  826.                                   instance=new_object, prefix=prefix)
File "/usr/lib64/python2.6/site-packages/django/forms/models.py" in __init__
  724.                                                 queryset=qs)
File "/usr/lib64/python2.6/site-packages/django/forms/models.py" in __init__
  459.         super(BaseModelFormSet, self).__init__(**defaults)
File "/usr/lib64/python2.6/site-packages/django/forms/formsets.py" in __init__
  44.         self._construct_forms()
File "/usr/lib64/python2.6/site-packages/django/forms/formsets.py" in _construct_forms
  88.             self.forms.append(self._construct_form(i))
File "/usr/lib64/python2.6/site-packages/django/forms/models.py" in _construct_form
  737.         form = super(BaseInlineFormSet, self)._construct_form(i, **kwargs)
File "/usr/lib64/python2.6/site-packages/django/forms/models.py" in _construct_form
  475.             pk = self.data[pk_key]
File "/usr/lib64/python2.6/site-packages/django/utils/datastructures.py" in __getitem__
  203.             raise MultiValueDictKeyError, "Key %r not found in %r" % (key, self)

Attachments (1)

models.py (4.0 KB ) - added by bruce@… 14 years ago.

Download all attachments as: .zip

Change History (24)

by bruce@…, 14 years ago

Attachment: models.py added

comment:1 by bruce@…, 14 years ago

Note: this error occurs whether you specify auto_created=True or auto_created=False, for Book, Author, and UUIDField (I have tried all 8 combinations of auto_created on and off for all three types).

comment:2 by bruce@…, 14 years ago

this is related to #8813

comment:3 by bruce@…, 14 years ago

Full error message:

MultiValueDictKeyError at /admin/gamedata/book/7432e312-d39b-11de-913b-00188b8e3ea8/

Key 'author_set-0-id' not found in <QueryDict: {u'_save': [u'Save'], u'author_set-TOTAL_FORMS': [u'5'], u'author_set-0-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'title': [u'book1'], u'author_set-0-name': [u'author1'], u'author_set-3-name': [u''], u'author_set-2-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'author_set-INITIAL_FORMS': [u'2'], u'author_set-4-name': [u''], u'author_set-2-name': [u''], u'author_set-3-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'author_set-1-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'author_set-4-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'author_set-1-name': [u'authro2']}>

Request Method: POST
Request URL: http://127.0.0.1:8000/admin/gamedata/book/7432e312-d39b-11de-913b-00188b8e3ea8/
Exception Type: MultiValueDictKeyError
Exception Value:

Key 'author_set-0-id' not found in <QueryDict: {u'_save': [u'Save'], u'author_set-TOTAL_FORMS': [u'5'], u'author_set-0-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'title': [u'book1'], u'author_set-0-name': [u'author1'], u'author_set-3-name': [u''], u'author_set-2-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'author_set-INITIAL_FORMS': [u'2'], u'author_set-4-name': [u''], u'author_set-2-name': [u''], u'author_set-3-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'author_set-1-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'author_set-4-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'author_set-1-name': [u'authro2']}>

Exception Location: /usr/lib64/python2.6/site-packages/django/utils/datastructures.py in getitem, line 203
Python Executable: /usr/bin/python2.6
Python Version: 2.6.2
Python Path: ['/usr/local/home/bruce/game/trunk/admin', '/usr/lib64/python26.zip', '/usr/lib64/python2.6', '/usr/lib64/python2.6/plat-linux2', '/usr/lib64/python2.6/lib-tk', '/usr/lib64/python2.6/lib-old', '/usr/lib64/python2.6/lib-dynload', '/usr/lib64/python2.6/site-packages', '/usr/lib64/python2.6/site-packages/Numeric', '/usr/lib64/python2.6/site-packages/PIL', '/usr/lib64/python2.6/site-packages/gst-0.10', '/usr/lib64/python2.6/site-packages/gtk-2.0', '/usr/lib64/portage/pym']
Server time: Tue, 17 Nov 2009 11:19:20 -0600

Environment:

Request Method: POST
Request URL: http://127.0.0.1:8000/admin/gamedata/book/7432e312-d39b-11de-913b-00188b8e3ea8/
Django Version: 1.2 pre-alpha
Python Version: 2.6.2
Installed Applications:
['django.contrib.auth',

'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.admin',
'admin.gamedata',
'admin.django_evolution']

Installed Middleware:
('django.middleware.common.CommonMiddleware',

'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware')

Traceback:
File "/usr/lib64/python2.6/site-packages/django/core/handlers/base.py" in get_response

  1. response = callback(request, *callback_args, callback_kwargs)

File "/usr/lib64/python2.6/site-packages/django/contrib/admin/options.py" in wrapper

  1. return self.admin_site.admin_view(view)(*args, kwargs)

File "/usr/lib64/python2.6/site-packages/django/utils/decorators.py" in call

  1. return self.decorator(self.func)(*args, kwargs)

File "/usr/lib64/python2.6/site-packages/django/views/decorators/cache.py" in _wrapped_view_func

  1. response = view_func(request, *args, kwargs)

File "/usr/lib64/python2.6/site-packages/django/contrib/admin/sites.py" in inner

  1. return view(request, *args, kwargs)

File "/usr/lib64/python2.6/site-packages/django/db/transaction.py" in _commit_on_success

  1. res = func(*args, kw)

File "/usr/lib64/python2.6/site-packages/django/contrib/admin/options.py" in change_view

  1. instance=new_object, prefix=prefix)

File "/usr/lib64/python2.6/site-packages/django/forms/models.py" in init

  1. queryset=qs)

File "/usr/lib64/python2.6/site-packages/django/forms/models.py" in init

  1. super(BaseModelFormSet, self).init(defaults)

File "/usr/lib64/python2.6/site-packages/django/forms/formsets.py" in init

  1. self._construct_forms()

File "/usr/lib64/python2.6/site-packages/django/forms/formsets.py" in _construct_forms

  1. self.forms.append(self._construct_form(i))

File "/usr/lib64/python2.6/site-packages/django/forms/models.py" in _construct_form

  1. form = super(BaseInlineFormSet, self)._construct_form(i, kwargs)

File "/usr/lib64/python2.6/site-packages/django/forms/models.py" in _construct_form

  1. pk = self.data[pk_key]

File "/usr/lib64/python2.6/site-packages/django/utils/datastructures.py" in getitem

  1. raise MultiValueDictKeyError, "Key %r not found in %r" % (key, self)

Exception Type: MultiValueDictKeyError at /admin/gamedata/book/7432e312-d39b-11de-913b-00188b8e3ea8/
Exception Value: Key 'author_set-0-id' not found in <QueryDict: {u'_save': [u'Save'], u'author_set-TOTAL_FORMS': [u'5'], u'author_set-0-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'title': [u'book1'], u'author_set-0-name': [u'author1'], u'author_set-3-name': [u''], u'author_set-2-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'author_set-INITIAL_FORMS': [u'2'], u'author_set-4-name': [u''], u'author_set-2-name': [u''], u'author_set-3-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'author_set-1-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'author_set-4-book': [u'7432e312-d39b-11de-913b-00188b8e3ea8'], u'author_set-1-name': [u'authro2']}>

comment:4 by Alex Gaynor, 14 years ago

Description: modified (diff)

Please use preview.

comment:5 by bruce_s, 14 years ago

What do you mean by use preview?

Here is the cut-and-paste output from django:

Environment:

Request Method: POST
Request URL: http://localhost/admin/gamedata/gamedata/book/8016d938-e9e2-11de-8ec3-00188b8e3ea8/
Django Version: 1.2 pre-alpha
Python Version: 2.6.4
Installed Applications:
['django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.admin',
 'admin.django_evolution',
 'admin.gamedata']
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware')


Traceback:
File "/usr/lib64/python2.6/site-packages/django/core/handlers/base.py" in get_response
  92.                 response = callback(request, *callback_args, **callback_kwargs)
File "/usr/lib64/python2.6/site-packages/django/contrib/admin/options.py" in wrapper
  226.                 return self.admin_site.admin_view(view)(*args, **kwargs)
File "/usr/lib64/python2.6/site-packages/django/utils/decorators.py" in __call__
  23.         return self.decorator(self.func)(*args, **kwargs)
File "/usr/lib64/python2.6/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
  70.         response = view_func(request, *args, **kwargs)
File "/usr/lib64/python2.6/site-packages/django/contrib/admin/sites.py" in inner
  186.             return view(request, *args, **kwargs)
File "/usr/lib64/python2.6/site-packages/django/db/transaction.py" in _commit_on_success
  240.                 res = func(*args, **kw)
File "/usr/lib64/python2.6/site-packages/django/contrib/admin/options.py" in change_view
  826.                                   instance=new_object, prefix=prefix)
File "/usr/lib64/python2.6/site-packages/django/forms/models.py" in __init__
  724.                                                 queryset=qs)
File "/usr/lib64/python2.6/site-packages/django/forms/models.py" in __init__
  459.         super(BaseModelFormSet, self).__init__(**defaults)
File "/usr/lib64/python2.6/site-packages/django/forms/formsets.py" in __init__
  44.         self._construct_forms()
File "/usr/lib64/python2.6/site-packages/django/forms/formsets.py" in _construct_forms
  88.             self.forms.append(self._construct_form(i))
File "/usr/lib64/python2.6/site-packages/django/forms/models.py" in _construct_form
  737.         form = super(BaseInlineFormSet, self)._construct_form(i, **kwargs)
File "/usr/lib64/python2.6/site-packages/django/forms/models.py" in _construct_form
  475.             pk = self.data[pk_key]
File "/usr/lib64/python2.6/site-packages/django/utils/datastructures.py" in __getitem__
  203.             raise MultiValueDictKeyError, "Key %r not found in %r" % (key, self)

Exception Type: MultiValueDictKeyError at /gamedata/gamedata/book/8016d938-e9e2-11de-8ec3-00188b8e3ea8/
Exception Value: Key 'author_set-0-id' not found in <QueryDict: {u'author_set-TOTAL_FORMS': [u'5'], u'author_set-0-book': [u'8016d938-e9e2-11de-8ec3-00188b8e3ea8'], u'title': [u'test title'], u'author_set-0-name': [u'author1'], u'author_set-3-name': [u''], u'author_set-2-book': [u'8016d938-e9e2-11de-8ec3-00188b8e3ea8'], u'_addanother': [u'Save and add another'], u'author_set-INITIAL_FORMS': [u'2'], u'author_set-4-name': [u''], u'author_set-2-name': [u'asdasd'], u'author_set-3-book': [u'8016d938-e9e2-11de-8ec3-00188b8e3ea8'], u'author_set-1-book': [u'8016d938-e9e2-11de-8ec3-00188b8e3ea8'], u'author_set-4-book': [u'8016d938-e9e2-11de-8ec3-00188b8e3ea8'], u'author_set-1-name': [u'author2']}>

comment:6 by Russell Keith-Magee, 14 years ago

milestone: 1.2
Triage Stage: UnreviewedAccepted

comment:7 by jacek99@…, 14 years ago

Getting the same error on one-to-many relationships with an existing Oracle schema (i.e. all entities are managed = False and generated via inspectdb). Stopped our Django implementation in its tracks :-(

comment:8 by Russell Keith-Magee, 14 years ago

Component: Uncategorizeddjango.contrib.admin

comment:9 by j.states@…, 14 years ago

Yes, I'm getting the same error - but don't even know were to start looking for the solution?

comment:10 by matiasb, 14 years ago

I think the problem could be in the definition of the UUIDField in the attached file. There, the id (an AutoField) is being replaced with an UUIDField, thus this field should work as an auto field. Then, adding the following to the UUIDField class definition solves the issue:

    def contribute_to_class(self, cls, name):
        assert not cls._meta.has_auto_field, "A model can't have more than one AutoField."
        super(UUIDField, self).contribute_to_class(cls, name)
        cls._meta.has_auto_field = True
        cls._meta.auto_field = self

What was the problem? When generating the template for inline forms, as the Author instances didn't have an auto_field, there wasn't any hidden field to relate the shown Author instance with the previously saved Author when editing a Book (in stacked.html and tabular.html templates):

{% if inline_admin_form.has_auto_field %}{{ inline_admin_form.pk_field.field }}{% endif %}

However, the saving view expects the 'author_set-0-id' field with the uuid (primary key) of the author to be updated. I'm assuming the if tag in the template is needed to be there, as defined.

comment:11 by John_Blaze, 14 years ago

Hrm - what happens if you have 2 UUIDField(s) in your model?

comment:12 by bruce_s, 14 years ago

For our models, we always use "id" as the primary key, so a slight modification of the above suggestion works for us:

    def contribute_to_class(self, cls, name):
        if name == "id": 
            assert not cls._meta.has_auto_field, "A model can't have more than one AutoField: %s %s %s; have %s" % (self,cls,name,cls._meta.auto_field)
            super(UUIDField, self).contribute_to_class(cls, name)
            cls._meta.has_auto_field = True
            cls._meta.auto_field = self
        else:
            super(UUIDField, self).contribute_to_class(cls, name)

Is there a better way to determine if a given field is the primary key?

comment:13 by John_Blaze, 14 years ago

Nice thought - I created was creating a UUIDForeignKey.

comment:14 by Jacob, 14 years ago

Resolution: invalid
Status: newclosed

It's clear to me from the description that this is an improperly written uuid field class. As suggested, the fix goes there.

comment:15 by atkinsonr, 14 years ago

Resolution: invalid
Status: closedreopened

I get the same error message; steps to replicate are the same as the OP, but I am generating my UUID primary key as a CharField from an abstract base class like this:

class UUIDModel(models.Model):
    """
        Inherit from this abstract base to use UUID as a primary key in models
    """
    id = models.CharField(max_length=36, primary_key=True, blank=True, editable=False)

    def save(self, *args, **kwargs):
        if not self.id:
            self.id = str(uuid.uuid1())
        super(UUIDModel, self).save()

    class Meta:
        abstract = True

Therefore I don't think that this issue is invalid.

Stack trace attached: http://dpaste.org/fj0h/

comment:16 by anonymous, 14 years ago

milestone: 1.2

comment:17 by domguard, 13 years ago

Version: 1.11.2

Having the very same problem using the django-extensions UUIDField()

comment:18 by domguard, 13 years ago

You can reproduce the bug using django_extensions UUIDField() implementation using this setup :

using : django 1.2.3 , django-extensions 0.5, PGSQL db with psycopg2

in settings.py

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.admin',
    'django_extensions',
    'myapp',
)

in myapp/models.py

from django.db import models
from django_extensions.db import fields as exfields

class Worker(models.Model):
    id = exfields.UUIDField(primary_key=True)
    name = models.CharField(blank=True, max_length=100)
    def __unicode__(self):
        return(self.name)

class Task(models.Model):
    id = exfields.UUIDField(primary_key=True)
    description = models.CharField(blank=True, max_length=100)
    workers = models.ManyToManyField(Worker, through="Todo")
    def __unicode__(self):
        return(self.description)

class Todo(models.Model):
    id = exfields.UUIDField(primary_key=True)
    worker = models.ForeignKey(Worker)
    task = models.ForeignKey(Task)

in myapp/admin.py

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

class WorkerAdmin(admin.ModelAdmin):
    pass

class TodoInline(admin.TabularInline):
    model = Todo
    fk_name = 'task'
    raw_id_fields = ('worker',)
    extra = 1
    
class TaskAdmin(admin.ModelAdmin):
    inlines = (TodoInline,)

admin.site.register(Worker,WorkerAdmin)
admin.site.register(Task,TaskAdmin)

Once db synced and admin urls setup, foillow these steps to reproduce the bug :

  1. Log into admin, add some workers
  2. Go to Task admin, add a task, add a related worker to it, save
  3. Go back to this same task admin page, and just try to save again, or add a worker and save, you got :

MultiValueDictKeyError at /admin/myapp/task/c64af3b5-f6e4-11df-869c-001cb3bc281a/

"Key 'todo_set-0-id' not found in <QueryDict: .....>"

https://gist.github.com/711535

comment:19 by Ramiro Morales, 13 years ago

@atkinsonr, @quinode:

You don't tell us if he UUID field implementation you use implements the fix matiasb comment details (or a similar more general one). If not please implement it, if it's a filed part of another project test and contribute such a fix to it (or point the author to this ticket), you re the ones using (or in need to use it) it and you are the ones in the better position to get it working with real code. Saying It doesn't work for me either but not making clear you've read just the ticket description or all the discussion isn't of too much help.

comment:20 by domguard, 13 years ago

You're completely true.
However, I'm not there right now : I use django and Python since a month now, and when I peek in those files, I can just measure the learning gap ...
I tried to adapt the patch but it resulted in errors really too weird for me, I'll try again, period

comment:21 by domguard, 13 years ago

@ramiro :
Ok, the matiasb fix (bruce_s version for me) finally works with the django_extension UUIDField() implementation too.
I was getting errors because of another hack on a particular model.
I'm currently asking for the fix to be added to the django_extension uuid field.

@atkinsonr:
Rather than defining yourself your UUIDfield in your abstract model, you could try to use django_extensions with the fix

Now, I'm not sure is this can be called "invalid" or "fixed"
If I understand what the fix does, it sets *again* the _meta.auto_field and _meta.has_auto_field that should have been set by django itself
Is this happening because Django skip this process when a CharField is given as pk ?
(Or is it that ALL the people writing UUIDFields are all wrong ?)

comment:22 by domguard, 13 years ago

Resolution: fixed
Status: reopenedclosed

@ bruce_s :
Another way to tell if the UUID field being added to the model is a primary key :

    def contribute_to_class(self, cls, name):
        if self.primary_key == True: 
            assert not cls._meta.has_auto_field, "A model can't have more than one AutoField: %s %s %s; have %s" % (self,cls,name,cls._meta.auto_field)
            super(UUIDField, self).contribute_to_class(cls, name)
            cls._meta.has_auto_field = True
            cls._meta.auto_field = self
        else:
            super(UUIDField, self).contribute_to_class(cls, name)

@atkinsonr :
I also use an UUIDField() in an abstract model, it's not a problem, you should really check your field implementation or use the django_extensions one.

Re-setting this issue to "fixed"

comment:23 by nickname123, 11 years ago

Cc: wgordonw1@… added
Easy pickings: unset
Severity: Normal
Type: Uncategorized
UI/UX: unset

per discussion on #django-dev I have opened a new ticket: https://code.djangoproject.com/ticket/19888

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