Opened 3 years ago
Closed 3 years ago
#33927 closed Bug (fixed)
Rendering a read-only ArrayField with choices crashes.
| Reported by: | David Svenson | Owned by: | David Wobrock |
|---|---|---|---|
| Component: | contrib.admin | Version: | 3.2 |
| Severity: | Normal | Keywords: | |
| Cc: | David Wobrock | Triage Stage: | Ready for checkin |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
If an ArrayField is included in an admin.ModelAdmin and has_change_permission returns False (making the field read-only), an exception is thrown when the field is supposed to be rendered.
This is the stacktrace after Django tries to render the field in django/contrib/admin/templates/admin/includes/fieldset.html
Traceback (most recent call last):
File ".venv/lib/python3.10/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File ".venv/lib/python3.10/site-packages/django/core/handlers/base.py", line 204, in _get_response
response = response.render()
File ".venv/lib/python3.10/site-packages/django/template/response.py", line 105, in render
self.content = self.rendered_content
File ".venv/lib/python3.10/site-packages/django/template/response.py", line 83, in rendered_content
return template.render(context, self._request)
File ".venv/lib/python3.10/site-packages/django/template/backends/django.py", line 61, in render
return self.template.render(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 170, in render
return self._render(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 162, in _render
return self.nodelist.render(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 938, in render
bit = node.render_annotated(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File ".venv/lib/python3.10/site-packages/django/template/loader_tags.py", line 150, in render
return compiled_parent._render(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 162, in _render
return self.nodelist.render(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 938, in render
bit = node.render_annotated(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File ".venv/lib/python3.10/site-packages/django/template/loader_tags.py", line 150, in render
return compiled_parent._render(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 162, in _render
return self.nodelist.render(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 938, in render
bit = node.render_annotated(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File ".venv/lib/python3.10/site-packages/django/template/loader_tags.py", line 62, in render
result = block.nodelist.render(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 938, in render
bit = node.render_annotated(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File ".venv/lib/python3.10/site-packages/django/template/loader_tags.py", line 62, in render
result = block.nodelist.render(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 938, in render
bit = node.render_annotated(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File ".venv/lib/python3.10/site-packages/django/template/defaulttags.py", line 214, in render
nodelist.append(node.render_annotated(context))
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File ".venv/lib/python3.10/site-packages/django/template/loader_tags.py", line 195, in render
return template.render(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 172, in render
return self._render(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 162, in _render
return self.nodelist.render(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 938, in render
bit = node.render_annotated(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File ".venv/lib/python3.10/site-packages/django/template/defaulttags.py", line 214, in render
nodelist.append(node.render_annotated(context))
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File ".venv/lib/python3.10/site-packages/django/template/defaulttags.py", line 214, in render
nodelist.append(node.render_annotated(context))
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File ".venv/lib/python3.10/site-packages/django/template/defaulttags.py", line 315, in render
return nodelist.render(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 938, in render
bit = node.render_annotated(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File ".venv/lib/python3.10/site-packages/django/template/defaulttags.py", line 315, in render
return nodelist.render(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 938, in render
bit = node.render_annotated(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 988, in render
output = self.filter_expression.resolve(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 671, in resolve
obj = self.var.resolve(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 796, in resolve
value = self._resolve_lookup(context)
File ".venv/lib/python3.10/site-packages/django/template/base.py", line 858, in _resolve_lookup
current = current()
File ".venv/lib/python3.10/site-packages/django/contrib/admin/helpers.py", line 239, in contents
result_repr = display_for_field(value, f, self.empty_value_display)
File ".venv/lib/python3.10/site-packages/django/contrib/admin/utils.py", line 385, in display_for_field
return dict(field.flatchoices).get(value, empty_value_display)
Exception Type: TypeError at /admin/companies/company/1/change/
Exception Value: unhashable type: 'list'
I haven't given much thought to how to solve this but I guess either contents or display_for_field has to handle the ArrayField or there should be some way to call get_FOO_display in this case.
Change History (4)
comment:1 by , 3 years ago
| Summary: | Rendering an ArrayField as read-only in admin raises TypeError → Rendering a read-only ArrayField with choices crashes. |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
comment:2 by , 3 years ago
| Cc: | added |
|---|---|
| Has patch: | set |
| Owner: | changed from to |
| Status: | new → assigned |
comment:3 by , 3 years ago
| Triage Stage: | Accepted → Ready for checkin |
|---|
Thanks for the report.
ArrayFieldmust havechoicesto reproduce this issue, e.g.We could try to call
make_hashable()on theflatchoicesandvalue:django/contrib/admin/utils.py
field.flatchoices).get(value, empty_value_display)but this can cause a performance regression.