0

In the ModelAdmin of my application i want to change the inlines of a change_view based on a certain condition of the object.

class TextInline(generic.GenericStackedInline):
    model = Text

class ImageInline(generic.GenericStackedInline):
    model = Image

class VideoInline(generic.GenericStackedInline):
    model = Video

class PageAdmin(models.ModelAdmin):
    def add_view(self, request, form_url='', extra_context=None):
        self.inlines = []
        return super(PageAdmin, self).add_view(
            request, form_url, extra_context)

    def change_view(self, request, object_id, form_url='', extra_context=None):
        obj = Page.objects.get(id=object_id)

        if obj.page_type in ('foo', 'bar',):
            self.inlines = [TextInline]
        elif obj.page_type == 'baz':
            self.inlines = [ImageInline, VideoInline]

        return super(PageAdmin, self).change_view(
            request, object_id, form_url, extra_context)

The add_view works as expected, no inlines are displayed. The change_view also displays the correct inlines on initial load and the correct inline instances after the first save. When the page is saved another time an MultiValueDictKeyError is raised. Apparently complaining of the missing inline instances.

Traceback:
File "/path/to/django/core/handlers/base.py" in get_response
111.                         response = callback(request, *callback_args, **callback_kwargs)
File "/path/to/django/contrib/admin/options.py" in wrapper
366.                 return self.admin_site.admin_view(view)(*args, **kwargs)
File "/path/to/django/utils/decorators.py" in _wrapped_view
91.                     response = view_func(request, *args, **kwargs)
File "/path/to/django/views/decorators/cache.py" in _wrapped_view_func
89.         response = view_func(request, *args, **kwargs)
File "/path/to/django/contrib/admin/sites.py" in inner
196.             return view(request, *args, **kwargs)
File "/path/to/presentation/admin.py" in change_view
151.             request, object_id, form_url, extra_context)
File "/path/to/django/utils/decorators.py" in _wrapper
25.             return bound_func(*args, **kwargs)
File "/path/to/django/utils/decorators.py" in _wrapped_view
91.                     response = view_func(request, *args, **kwargs)
File "/path/to/django/utils/decorators.py" in bound_func
21.                 return func(self, *args2, **kwargs2)
File "/path/to/django/db/transaction.py" in inner
209.                 return func(*args, **kwargs)
File "/path/to/django/contrib/admin/options.py" in change_view
1049.                                   queryset=inline.queryset(request))
File "/path/to/django/contrib/contenttypes/generic.py" in __init__
402.             prefix=prefix
File "/path/to/django/forms/models.py" in __init__
424.         super(BaseModelFormSet, self).__init__(**defaults)
File "/path/to/django/forms/formsets.py" in __init__
50.         self._construct_forms()
File "/path/to/django/forms/formsets.py" in _construct_forms
115.             self.forms.append(self._construct_form(i))
File "/path/to/django/forms/models.py" in _construct_form
443.             pk = self.data[pk_key]
File "/path/to/django/utils/datastructures.py" in __getitem__
258.             raise MultiValueDictKeyError("Key %r not found in %r" % (key, self))

Exception Type: MultiValueDictKeyError at /admin/presentation/page/5/
Exception Value: "Key 'presentation-text-content_type-object_id-0-id' not found in <QueryDict: {u'status': [u'2'], u'presentation-text-content_type-object_id-1-text': [u'xxx'], u'title': [u'y'], u'presentation-text-content_type-object_id-0-text': [u'xx'], u'presentation-text-content_type-object_id-__prefix__-ordering': [u''], u'presentation-text-content_type-object_id-TOTAL_FORMS': [u'2'], u'presentation-text-content_type-object_id-0-ordering': [u''], u'presentation-text-content_type-object_id-1-ordering': [u''], u'presentation-text-content_type-object_id-__prefix__-text': [u''], u'presentation-text-content_type-object_id-MAX_NUM_FORMS': [u''], u'csrfmiddlewaretoken': [u'6f53e0394b9008494a53cf460826235c'], u'presentation': [u'1'], u'_continue': [u'Sichern und weiter bearbeiten'], u'presentation-text-content_type-object_id-INITIAL_FORMS': [u'1']}>"

My question is very similiar to this one which even provides a solution. Django 1.4 however changed the api, so that there is no ModelAdmin.inline_instances anymore.

In Django 1.4 you can use ModelAdmin.get_inline_instances() to retrieve a list of inline instances, but i can't figure out how to set them. Or is there anoher way of doing this in Django 1.4? There might be a reason for the api change.

Community
  • 1
  • 1
Dirk Eschler
  • 2,539
  • 1
  • 21
  • 41

1 Answers1

2

The error occurs at

File "/path/to/django/contrib/admin/options.py" in change_view
1049.                                   queryset=inline.queryset(request))

There the inline_instances has already been successfully generated.

By checking your POST

>>> post = {u'status': [u'2'], u'presentation-text-content_type-object_id-1-text': [u'xxx'], u'title': [u'y'], u'presentation-text-content_type-object_id-0-text': [u'xx'], u'presentation-text-content_type-object_id-__prefix__-ordering': [u''], u'presentation-text-content_type-object_id-TOTAL_FORMS': [u'2'], u'presentation-text-content_type-object_id-0-ordering': [u''], u'presentation-text-content_type-object_id-1-ordering': [u''], u'presentation-text-content_type-object_id-__prefix__-text': [u''], u'presentation-text-content_type-object_id-MAX_NUM_FORMS': [u''], u'csrfmiddlewaretoken': [u'6f53e0394b9008494a53cf460826235c'], u'presentation': [u'1'], u'_continue': [u'Sichern und weiter bearbeiten'], u'presentation-text-content_type-object_id-INITIAL_FORMS': [u'1']}
>>> sorted(post.keys())
[u'_continue',
 u'csrfmiddlewaretoken',
 u'presentation',
 u'presentation-text-content_type-object_id-0-ordering',
 u'presentation-text-content_type-object_id-0-text',
 u'presentation-text-content_type-object_id-1-ordering',
 u'presentation-text-content_type-object_id-1-text',
 u'presentation-text-content_type-object_id-INITIAL_FORMS',
 u'presentation-text-content_type-object_id-MAX_NUM_FORMS',
 u'presentation-text-content_type-object_id-TOTAL_FORMS',
 u'presentation-text-content_type-object_id-__prefix__-ordering',
 u'presentation-text-content_type-object_id-__prefix__-text',
 u'status',
 u'title']

There is not something like u'presentation-text-content_type-object_id-__prefix__-id' but your code expects one. So better to check the HTML, InlineModelAdmin and the model to find out why there is not such key in the POST.

okm
  • 23,575
  • 5
  • 83
  • 90
  • Resolved my problem. It turned out that my inline used a custom form that lacked a required field. Still don't quite understand how this ever worked on first save with one inline... In any case, thanks alot for pointing me in the right direction! – Dirk Eschler Jun 25 '12 at 15:16