Opened 3 hours ago
#36228 new Bug
ModelAdmin using non-default DB + RelatedOnlyFieldListFilter crashes
Reported by: | Ran Benita | Owned by: | |
---|---|---|---|
Component: | contrib.admin | Version: | 5.1 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Problem
I have a ModelAdmin
which makes all list and detail queries go to a non-default DB. It also uses a RelatedOnlyFieldListFilter
.
from django.contrib import admin class FooAdmin(admin.ModelAdmin): list_filter = ( ('my_field', admin.RelatedOnlyFieldListFilter), ) def get_queryset(self, request): queryset = super().get_queryset(request) if request.method == 'GET': queryset = queryset.using('other_db') return queryset
Loading the admin list page for this model crashes:
Traceback (most recent call last): [snipped] File "venv/lib/python3.11/site-packages/django/core/handlers/base.py", line 197, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/contrib/admin/options.py", line 718, in wrapper return self.admin_site.admin_view(view)(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/utils/decorators.py", line 188, in _view_wrapper result = _process_exception(request, e) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/utils/decorators.py", line 186, in _view_wrapper response = view_func(request, *args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/views/decorators/cache.py", line 80, in _view_wrapper response = view_func(request, *args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/contrib/admin/sites.py", line 241, in inner return view(request, *args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/utils/decorators.py", line 48, in _wrapper return bound_method(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/utils/decorators.py", line 188, in _view_wrapper result = _process_exception(request, e) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/utils/decorators.py", line 186, in _view_wrapper response = view_func(request, *args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/contrib/admin/options.py", line 2001, in changelist_view cl = self.get_changelist_instance(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/contrib/admin/options.py", line 866, in get_changelist_instance return ChangeList( ^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/contrib/admin/views/main.py", line 145, in __init__ self.queryset = self.get_queryset(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/contrib/admin/views/main.py", line 545, in get_queryset ) = self.get_filters(request) ^^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/contrib/admin/views/main.py", line 216, in get_filters spec = field_list_filter_class( ^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/contrib/admin/filters.py", line 232, in __init__ self.lookup_choices = self.field_choices(field, request, model_admin) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/contrib/admin/filters.py", line 649, in field_choices return field.get_choices( ^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/db/models/fields/__init__.py", line 1076, in get_choices return (blank_choice if include_blank else []) + [ ^ File "venv/lib/python3.11/site-packages/django/db/models/query.py", line 400, in __iter__ self._fetch_all() File "venv/lib/python3.11/site-packages/django/db/models/query.py", line 1928, in _fetch_all self._result_cache = list(self._iterable_class(self)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/db/models/query.py", line 91, in __iter__ results = compiler.execute_sql( ^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 1561, in execute_sql sql, params = self.as_sql() ^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 775, in as_sql self.compile(self.where) if self.where is not None else ("", []) ^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 557, in compile sql, params = node.as_sql(self, self.connection) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/db/models/sql/where.py", line 151, in as_sql sql, params = compiler.compile(child) ^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 557, in compile sql, params = node.as_sql(self, self.connection) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/db/models/lookups.py", line 536, in as_sql return super().as_sql(compiler, connection) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/db/models/lookups.py", line 246, in as_sql rhs_sql, rhs_params = self.process_rhs(compiler, connection) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "venv/lib/python3.11/site-packages/django/db/models/lookups.py", line 502, in process_rhs raise ValueError( ValueError: Subqueries aren't allowed across different databases. Force the inner query to be evaluated using `list(inner_query)`.
I believe the problem happens because:
RelatedOnlyFieldListFilter
takes the queryset from the admin, which is usingother_db
- Passes it to
Field.get_choices()
in thelimit_choices_to
parameter, which translates to a query lookup Field.get_choices()
runs the query against the default DB, while the lookup is againstother_db
Proposed Solution
- Add a
using
parameter toField.get_choices()
- Pass
using=qs.db
toField.get_choices()
inRelatedOnlyFieldListFilter
If acceptable I can try to submit a PR doing this.
Note:
See TracTickets
for help on using tickets.