#36228 closed Bug (invalid)
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:
RelatedOnlyFieldListFiltertakes the queryset from the admin, which is usingother_db- Passes it to
Field.get_choices()in thelimit_choices_toparameter, 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
usingparameter toField.get_choices() - Pass
using=qs.dbtoField.get_choices()inRelatedOnlyFieldListFilter
If acceptable I can try to submit a PR doing this.
Change History (2)
comment:1 by , 8 months ago
| Resolution: | → invalid |
|---|---|
| Status: | new → closed |
comment:2 by , 8 months ago
Thanks for taking a look!
The page you linked regarding the admin multi-db does recommend the approach I am using -- overriding get_queryset to add using(). That example will crash if RelatedOnlyFieldListFilter is added.
Note:
See TracTickets
for help on using tickets.
Hi Ran
As documented, the Django admin doesn't have any explicit support for multiple databases: https://docs.djangoproject.com/en/5.1/topics/db/multi-db/#exposing-multiple-databases-in-django-s-admin-interface
I also think you might want to solve this at a Router level using db_for_read: https://docs.djangoproject.com/en/5.1/topics/db/multi-db/#db_for_read
If you need support, please use one of our user support channels from this link.