#34481: Admin check for reversed foreign key used in "list_display"
------------------------------------------+------------------------
Reporter: Natalia Bidart | Owner: nobody
Type: Uncategorized | Status: new
Component: Uncategorized | Version: dev
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
------------------------------------------+------------------------
Currently the admin site checks and reports an `admin.E109` system check
error when a `ManyToManyField` is declared within the `list_display`
values.
But, when a reversed foreign key is used there is no system error
reported:
{{{
System check identified no issues (0 silenced).
April 10, 2023 - 19:04:29
Django version 5.0.dev20230410064954, using settings
'projectfromrepo.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.
}}}
and visiting the admin site for the relevant model results in the
following error:
{{{
TypeError:
create_reverse_many_to_one_manager.<locals>.RelatedManager.__call__()
missing 1 required keyword-only argument: 'manager'
[10/Apr/2023 19:30:40] "GET /admin/testapp/question/ HTTP/1.1" 500 415926
}}}
Ideally, using a reversed foreign key would also result in a system check
error instead of a 500 response.
To reproduce, follow the `Question` and `Choice` models from the Django
Tutorial and add the following to the `QuestionAdmin`:
{{{
list_display = ["question_text", "choice_set"]
}}}
Then, visit `/admin/testapp/question/` and the following traceback is
returned:
{{{
Internal Server Error: /admin/testapp/question/
Traceback (most recent call last):
File "/some/path/django/django/db/models/options.py", line 681, in
get_field
return self.fields_map[field_name]
~~~~~~~~~~~~~~~^^^^^^^^^^^^
KeyError: 'choice_set'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/some/path/django/django/contrib/admin/utils.py", line 288, in
lookup_field
f = _get_non_gfk_field(opts, name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/contrib/admin/utils.py", line 319, in
_get_non_gfk_field
field = opts.get_field(name)
^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/db/models/options.py", line 683, in
get_field
raise FieldDoesNotExist(
django.core.exceptions.FieldDoesNotExist: Question has no field named
'choice_set'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/some/path/django/django/core/handlers/exception.py", line 55, in
inner
response = get_response(request)
^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/core/handlers/base.py", line 220, in
_get_response
response = response.render()
^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/response.py", line 111, in
render
self.content = self.rendered_content
^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/response.py", line 89, in
rendered_content
return template.render(context, self._request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/backends/django.py", line 61, in
render
return self.template.render(context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 171, in render
return self._render(context)
^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 163, in _render
return self.nodelist.render(context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 1001, in render
return SafeString("".join([node.render_annotated(context) for node in
self]))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 1001, in
<listcomp>
return SafeString("".join([node.render_annotated(context) for node in
self]))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 962, in
render_annotated
return self.render(context)
^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/loader_tags.py", line 157, in
render
return compiled_parent._render(context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 163, in _render
return self.nodelist.render(context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 1001, in render
return SafeString("".join([node.render_annotated(context) for node in
self]))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 1001, in
<listcomp>
return SafeString("".join([node.render_annotated(context) for node in
self]))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 962, in
render_annotated
return self.render(context)
^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/loader_tags.py", line 157, in
render
return compiled_parent._render(context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 163, in _render
return self.nodelist.render(context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 1001, in render
return SafeString("".join([node.render_annotated(context) for node in
self]))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 1001, in
<listcomp>
return SafeString("".join([node.render_annotated(context) for node in
self]))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 962, in
render_annotated
return self.render(context)
^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/loader_tags.py", line 63, in
render
result = block.nodelist.render(context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 1001, in render
return SafeString("".join([node.render_annotated(context) for node in
self]))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 1001, in
<listcomp>
return SafeString("".join([node.render_annotated(context) for node in
self]))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 962, in
render_annotated
return self.render(context)
^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/loader_tags.py", line 63, in
render
result = block.nodelist.render(context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 1001, in render
return SafeString("".join([node.render_annotated(context) for node in
self]))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 1001, in
<listcomp>
return SafeString("".join([node.render_annotated(context) for node in
self]))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/base.py", line 962, in
render_annotated
return self.render(context)
^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/contrib/admin/templatetags/base.py", line
45, in render
return super().render(context)
^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/template/library.py", line 258, in render
_dict = self.func(*resolved_args, **resolved_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File
"/some/path/django/django/contrib/admin/templatetags/admin_list.py", line
340, in result_list
"results": list(results(cl)),
^^^^^^^^^^^^^^^^^
File
"/some/path/django/django/contrib/admin/templatetags/admin_list.py", line
316, in results
yield ResultList(None, items_for_result(cl, res, None))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File
"/some/path/django/django/contrib/admin/templatetags/admin_list.py", line
307, in __init__
super().__init__(*items)
File
"/some/path/django/django/contrib/admin/templatetags/admin_list.py", line
217, in items_for_result
f, attr, value = lookup_field(field_name, result, cl.model_admin)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/some/path/django/django/contrib/admin/utils.py", line 301, in
lookup_field
value = attr()
^^^^^^
TypeError:
create_reverse_many_to_one_manager.<locals>.RelatedManager.__call__()
missing 1 required keyword-only argument: 'manager'
[10/Apr/2023 19:30:40] "GET /admin/testapp/question/ HTTP/1.1" 500 415926
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/34481>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/010701876caac625-bcd9ae32-f20b-4548-ac10-6741fbb24a76-000000%40eu-central-1.amazonses.com.