Opened 6 years ago

Closed 5 years ago

Last modified 4 years ago

#12700 closed (fixed)

readonly_fields specified on inline model admin cause KeyError since r12297

Reported by: kmtracey Owned by: nobody
Component: Uncategorized Version: master
Severity: Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation:
Needs tests: Patch needs improvement:
Easy pickings: UI/UX:

Description

Given these models:

class Puzzle(models.Model):
    title = models.CharField(max_length=240)

class Clue(models.Model):
    puzzle = models.ForeignKey(Puzzle)
    text = models.CharField(max_length=240)
    num = models.IntegerField()

and these admin defs:

from ttt.models import Puzzle, Clue

class ClueInline(admin.TabularInline):
    model = Clue
    readonly_fields = ('num',)

class PuzzleAdmin(admin.ModelAdmin):
    inlines = [ClueInline]

admin.site.register(Puzzle, PuzzleAdmin)

an attempt to bring up and add or change page for a Puzzle will result in:

Environment:

Request Method: GET
Request URL: http://localhost:6666/admin/ttt/puzzle/add/
Django Version: 1.2 alpha 1 SVN-12297
Python Version: 2.5.2
Installed Applications:
['django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.admin',
 'django.contrib.admindocs',
 'ttt',
 'debug_toolbar']
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.middleware.doc.XViewMiddleware',
 'django.middleware.transaction.TransactionMiddleware',
 'debug_toolbar.middleware.DebugToolbarMiddleware')

Template error:
In template /home/kmt/django/trunk/django/contrib/admin/templates/admin/edit_inline/tabular.html, error at line 33
   Caught an exception while rendering: "Key 'num' not found in Form"
   23 :         <tr class="{% cycle "row1" "row2" %} {% if inline_admin_form.original or inline_admin_form.show_url %}has_original{% endif %}{% if forloop.last %} empty-form{% endif %}"
   24 :              id="{{ inline_admin_formset.formset.prefix }}{% if not forloop.last %}{{ forloop.counter }}{% else %}-empty{% endif %}">
   25 :         <td class="original">
   26 :           {% if inline_admin_form.original or inline_admin_form.show_url %}<p>
   27 :           {% if inline_admin_form.original %} {{ inline_admin_form.original }}{% endif %}
   28 :           {% if inline_admin_form.show_url %}<a href="../../../r/{{ inline_admin_form.original_content_type_id }}/{{ inline_admin_form.original.id }}/">{% trans "View on site" %}</a>{% endif %}
   29 :             </p>{% endif %}
   30 :           {% if inline_admin_form.has_auto_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
   31 :           {{ inline_admin_form.fk_field.field }}
   32 :           {% spaceless %}
   33 :            {% for fieldset in inline_admin_form %} 
   34 :             {% for line in fieldset %}
   35 :               {% for field in line %}
   36 :                 {% if field.is_hidden %} {{ field.field }} {% endif %}
   37 :               {% endfor %}
   38 :             {% endfor %}
   39 :           {% endfor %}
   40 :           {% endspaceless %}
   41 :         </td>
   42 :         {% for fieldset in inline_admin_form %}
   43 :           {% for line in fieldset %}

Traceback:
File "/home/kmt/django/trunk/django/core/handlers/base.py" in get_response
  101.                     response = callback(request, *callback_args, **callback_kwargs)
File "/home/kmt/django/trunk/django/contrib/admin/options.py" in wrapper
  238.                 return self.admin_site.admin_view(view)(*args, **kwargs)
File "/home/kmt/django/trunk/django/utils/decorators.py" in __call__
  36.         return self.decorator(self.func)(*args, **kwargs)
File "/home/kmt/django/trunk/django/utils/decorators.py" in _wrapped_view
  86.                     response = view_func(request, *args, **kwargs)
File "/home/kmt/django/trunk/django/utils/decorators.py" in __call__
  36.         return self.decorator(self.func)(*args, **kwargs)
File "/home/kmt/django/trunk/django/views/decorators/cache.py" in _wrapped_view_func
  70.         response = view_func(request, *args, **kwargs)
File "/home/kmt/django/trunk/django/contrib/admin/sites.py" in inner
  190.             return view(request, *args, **kwargs)
File "/home/kmt/django/trunk/django/utils/decorators.py" in _wrapped_view
  86.                     response = view_func(request, *args, **kwargs)
File "/home/kmt/django/trunk/django/db/transaction.py" in _commit_on_success
  295.                     res = func(*args, **kw)
File "/home/kmt/django/trunk/django/contrib/admin/options.py" in add_view
  839.         return self.render_change_form(request, context, form_url=form_url, add=True)
File "/home/kmt/django/trunk/django/contrib/admin/options.py" in render_change_form
  631.         ], context, context_instance=context_instance)
File "/home/kmt/django/trunk/django/shortcuts/__init__.py" in render_to_response
  20.     return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
File "/home/kmt/django/trunk/django/template/loader.py" in render_to_string
  173.     return t.render(context_instance)
File "/home/kmt/django/trunk/django/template/__init__.py" in render
  184.             return self._render(context)
File "/home/kmt/django/trunk/django/template/__init__.py" in _render
  178.         return self.nodelist.render(context)
File "/home/kmt/django/trunk/django/template/__init__.py" in render
  787.                 bits.append(self.render_node(node, context))
File "/home/kmt/django/trunk/django/template/debug.py" in render_node
  72.             result = node.render(context)
File "/home/kmt/django/trunk/django/template/loader_tags.py" in render
  128.         return compiled_parent._render(context)
File "/home/kmt/django/trunk/django/template/__init__.py" in _render
  178.         return self.nodelist.render(context)
File "/home/kmt/django/trunk/django/template/__init__.py" in render
  787.                 bits.append(self.render_node(node, context))
File "/home/kmt/django/trunk/django/template/debug.py" in render_node
  72.             result = node.render(context)
File "/home/kmt/django/trunk/django/template/loader_tags.py" in render
  128.         return compiled_parent._render(context)
File "/home/kmt/django/trunk/django/template/__init__.py" in _render
  178.         return self.nodelist.render(context)
File "/home/kmt/django/trunk/django/template/__init__.py" in render
  787.                 bits.append(self.render_node(node, context))
File "/home/kmt/django/trunk/django/template/debug.py" in render_node
  72.             result = node.render(context)
File "/home/kmt/django/trunk/django/template/loader_tags.py" in render
  62.             result = block.nodelist.render(context)
File "/home/kmt/django/trunk/django/template/__init__.py" in render
  787.                 bits.append(self.render_node(node, context))
File "/home/kmt/django/trunk/django/template/debug.py" in render_node
  72.             result = node.render(context)
File "/home/kmt/django/trunk/django/template/defaulttags.py" in render
  176.                 nodelist.append(node.render(context))
File "/home/kmt/django/trunk/django/template/loader_tags.py" in render
  154.             return t.render(context)
File "/home/kmt/django/trunk/django/template/__init__.py" in render
  184.             return self._render(context)
File "/home/kmt/django/trunk/django/template/__init__.py" in _render
  178.         return self.nodelist.render(context)
File "/home/kmt/django/trunk/django/template/__init__.py" in render
  787.                 bits.append(self.render_node(node, context))
File "/home/kmt/django/trunk/django/template/debug.py" in render_node
  72.             result = node.render(context)
File "/home/kmt/django/trunk/django/template/defaulttags.py" in render
  176.                 nodelist.append(node.render(context))
File "/home/kmt/django/trunk/django/template/defaulttags.py" in render
  334.         return strip_spaces_between_tags(self.nodelist.render(context).strip())
File "/home/kmt/django/trunk/django/template/__init__.py" in render
  787.                 bits.append(self.render_node(node, context))
File "/home/kmt/django/trunk/django/template/debug.py" in render_node
  82.             raise wrapped

Exception Type: TemplateSyntaxError at /admin/ttt/puzzle/add/
Exception Value: Caught an exception while rendering: "Key 'num' not found in Form"

Original Traceback (most recent call last):
  File "/home/kmt/django/trunk/django/template/debug.py", line 72, in render_node
    result = node.render(context)
  File "/home/kmt/django/trunk/django/template/defaulttags.py", line 176, in render
    nodelist.append(node.render(context))
  File "/home/kmt/django/trunk/django/template/defaulttags.py", line 176, in render
    nodelist.append(node.render(context))
  File "/home/kmt/django/trunk/django/template/defaulttags.py", line 146, in render
    values = list(values)
  File "/home/kmt/django/trunk/django/contrib/admin/helpers.py", line 102, in __iter__
    yield AdminField(self.form, field, is_first=(i == 0))
  File "/home/kmt/django/trunk/django/contrib/admin/helpers.py", line 109, in __init__
    self.field = form[field] # A django.forms.BoundField instance
  File "/home/kmt/django/trunk/django/forms/forms.py", line 105, in __getitem__
    raise KeyError('Key %r not found in Form' % name)
KeyError: "Key 'num' not found in Form"

If I back off to r12296 the exception goes away, though there was something slightly wrong in the previous version also -- (None) is displayed for the values of num in the extra lines where new Clues could be entered. Not sure what should be shown, but probably not (None)

Change History (2)

comment:1 Changed 5 years ago by jezdez

  • Resolution set to fixed
  • Status changed from new to closed

(In [12368]) Fixed #12700 - Take read-only fields into account when rendering the empty form for dynamic inlines.

comment:2 Changed 4 years ago by jacob

  • milestone 1.2 deleted

Milestone 1.2 deleted

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