[Django] #36228: ModelAdmin using non-default DB + RelatedOnlyFieldListFilter crashes

9 views
Skip to first unread message

Django

unread,
Mar 4, 2025, 10:57:04 AM3/4/25
to django-...@googlegroups.com
#36228: ModelAdmin using non-default DB + RelatedOnlyFieldListFilter crashes
----------------------------+-----------------------------------------
Reporter: Ran Benita | Type: Bug
Status: new | Component: contrib.admin
Version: 5.1 | 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
----------------------------+-----------------------------------------
== Problem

I have a `ModelAdmin` which makes all list and detail queries go to a non-
default DB. It also uses a `RelatedOnlyFieldListFilter`.

{{{#!python
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
using `other_db`
- Passes it to `Field.get_choices()` in the `limit_choices_to` parameter,
which translates to a query lookup
- `Field.get_choices()` runs the query against the default DB, while the
lookup is against `other_db`

== Proposed Solution

- Add a `using` parameter to `Field.get_choices()`
- Pass `using=qs.db` to `Field.get_choices()` in
`RelatedOnlyFieldListFilter`

If acceptable I can try to submit a PR doing this.
--
Ticket URL: <https://code.djangoproject.com/ticket/36228>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Mar 5, 2025, 4:25:47 AM3/5/25
to django-...@googlegroups.com
#36228: ModelAdmin using non-default DB + RelatedOnlyFieldListFilter crashes
-------------------------------+--------------------------------------
Reporter: Ran Benita | Owner: (none)
Type: Bug | Status: closed
Component: contrib.admin | Version: 5.1
Severity: Normal | Resolution: invalid
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Changes (by Sarah Boyce):

* resolution: => invalid
* status: new => closed

Comment:

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
[https://docs.djangoproject.com/en/dev/faq/help/#how-do-i-do-x-why-
doesn-t-y-work-where-can-i-go-to-get-help this link].
--
Ticket URL: <https://code.djangoproject.com/ticket/36228#comment:1>

Django

unread,
Mar 5, 2025, 4:40:23 AM3/5/25
to django-...@googlegroups.com
#36228: ModelAdmin using non-default DB + RelatedOnlyFieldListFilter crashes
-------------------------------+--------------------------------------
Reporter: Ran Benita | Owner: (none)
Type: Bug | Status: closed
Component: contrib.admin | Version: 5.1
Severity: Normal | Resolution: invalid
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Comment (by Ran Benita):

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.
--
Ticket URL: <https://code.djangoproject.com/ticket/36228#comment:2>
Reply all
Reply to author
Forward
0 new messages