'Django custom ordering causes error for related model?

I have two models as follows:

class A(models.Model):
    # more fields here
    finished_at = models.DateTimeField(db_index=True, null=True, blank=True)

    class Meta:
        ordering = [
            models.F("finished_at").desc(nulls_first=True),
            "other_field",
        ]


class B(models.Model):
    a = models.ForeignKey(A, on_delete=models.CASCADE)

    class Meta:
        ordering = [
            "a"
        ]

And then when I try to delete A instances through the admin site, or when accessing B instances either through admin or command line it gives error: Cannot resolve keyword into field finished_at.

But if I remove the ordering on model A it works fine.

I could narrow down the issue, removing either "a" from B ordering or not using the models.F expression from A ordering will solve the issue.

Full stacktrace:


Django Version: 3.2.11
Python Version: 3.8.12
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'rest_framework',
 'corsheaders',
 'my-apps',
]
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'corsheaders.middleware.CorsMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback (most recent call last):
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/contrib/admin/options.py", line 616, in wrapper
    return self.admin_site.admin_view(view)(*args, **kwargs)
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/contrib/admin/sites.py", line 232, in inner
    return view(request, *args, **kwargs)
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/utils/decorators.py", line 43, in _wrapper
    return bound_method(*args, **kwargs)
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1815, in changelist_view
    'selection_note': _('0 of %(cnt)s selected') % {'cnt': len(cl.result_list)},
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/db/models/query.py", line 262, in __len__
    self._fetch_all()
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/db/models/query.py", line 1324, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/db/models/query.py", line 51, in __iter__
    results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1162, in execute_sql
    sql, params = self.as_sql()
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 513, in as_sql
    extra_select, order_by, group_by = self.pre_sql_setup()
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 56, in pre_sql_setup
    order_by = self.get_order_by()
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 372, in get_order_by
    resolved = expr.resolve_expression(self.query, allow_joins=True, reuse=None)
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/db/models/expressions.py", line 247, in resolve_expression
    c.set_source_expressions([
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/db/models/expressions.py", line 248, in <listcomp>
    expr.resolve_expression(query, allow_joins, reuse, summarize)
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/db/models/expressions.py", line 578, in resolve_expression
    return query.resolve_ref(self.name, allow_joins, reuse, summarize)
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/db/models/sql/query.py", line 1756, in resolve_ref
    join_info = self.setup_joins(field_list, self.get_meta(), self.get_initial_alias(), can_reuse=reuse)
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/db/models/sql/query.py", line 1625, in setup_joins
    path, final_field, targets, rest = self.names_to_path(
  File "BASE_DIR/.venv/lib/python3.8/site-packages/django/db/models/sql/query.py", line 1539, in names_to_path
    raise FieldError("Cannot resolve keyword '%s' into field. "

Exception Type: FieldError at /admin/some/path/
Exception Value: Cannot resolve keyword 'finished_at' into field. Choices are


Solution 1:[1]

Instead of putting the name of the related model, you have to address the id of the related model.

class B(models.Model):
    a = models.ForeignKey(A, on_delete=models.CASCADE)

    class Meta:
        ordering = [
            "a_id"
        ]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 mnislam01