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 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.

Change History (0)

Note: See TracTickets for help on using tickets.
Back to Top