Opened 2 years ago
Closed 2 years ago
#34012 closed Cleanup/optimization (fixed)
QuerySet.order_by() silently skips non-existing fields on related fields with Meta.ordering.
Reported by: | Klaas van Schelven | Owned by: | David Sanders |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 4.1 |
Severity: | Normal | Keywords: | |
Cc: | David Sanders | Triage Stage: | Ready for checkin |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Compare the following desirable behavior:
>>> SomeModel.objects.all().order_by("non_existing_field") Traceback (most recent call last): File "<console>", line 1, in <module> File "......lib/python3.10/site-packages/django/db/models/query.py", line 1149, in order_by obj.query.add_ordering(*field_names) File "......lib/python3.10/site-packages/django/db/models/sql/query.py", line 2016, in add_ordering self.names_to_path(item.split(LOOKUP_SEP), self.model._meta) File "......lib/python3.10/site-packages/django/db/models/sql/query.py", line 1562, in names_to_path raise FieldError("Cannot resolve keyword '%s' into field. " django.core.exceptions.FieldError: Cannot resolve keyword 'non_existing_field' into field. Choices are: [redacted]
with the following undesirable behavior:
>>> SomeModel.objects.all().order_by("some_foreign_key__non_existing_field") <QuerySet .... [ i.e. shows some results ]
Change History (11)
comment:1 by , 2 years ago
Component: | Uncategorized → Database layer (models, ORM) |
---|---|
Summary: | order_by silently skips non-existing fields of existing related fields → QuerySet.order_by() silently skips non-existing fields on related fields. |
Triage Stage: | Unreviewed → Accepted |
Type: | Uncategorized → Cleanup/optimization |
comment:2 by , 2 years ago
Cc: | added |
---|
fwiw I can't reproduce the issue on 4.1.1 🤔 …
Here's what I tried (full tracebacks omitted for brevity):
class Parent(Model): ... class Child(Model): parent = ForeignKey(Parent, on_delete=CASCADE) Child.objects.all().order_by('asdf') FieldError: Cannot resolve keyword 'asdf' into field. Choices are: id, parent, parent_id Child.objects.all().order_by('parent__id') <QuerySet []> Child.objects.all().order_by('parent__asdf') FieldError: Unsupported lookup 'asdf' for BigAutoField or join on the field not permitted, perhaps you meant df? During handling of the above exception, another exception occurred: FieldError: Cannot resolve keyword 'asdf' into field. Choices are: child, id
comment:3 by , 2 years ago
Good catch, this only happens when an explicit ordering is defined on the Parent
's Meta
:
from django.db import models class Parent(models.Model): class Meta: ordering = ["id"] class Child(models.Model): parent = models.ForeignKey(Parent, on_delete=models.CASCADE)
Reproducable up to Django 4.1.1
comment:4 by , 2 years ago
felixx this looks like an issue with overriding the foreign model's ordering.
If I repeat the test with Klaas' models and print the query it reveals it still attempts to use parent.id
:
class Parent(Model): class Meta: ordering = ["id"] class Child(Model): parent = ForeignKey(Parent, on_delete=CASCADE) print(Child.objects.all().order_by('parent__asdf').query) SELECT "sample_child"."id", "sample_child"."parent_id" FROM "sample_child" INNER JOIN "sample_parent" ON ("sample_child"."parent_id" = "sample_parent"."id") ORDER BY "sample_parent"."id" ASC
Edit: (I guess the question is whether Django should raise an error or continue onto ordering)
comment:5 by , 2 years ago
Has patch: | set |
---|---|
Owner: | changed from | to
Status: | new → assigned |
comment:6 by , 2 years ago
Version: | 4.0 → 4.1 |
---|
comment:7 by , 2 years ago
Summary: | QuerySet.order_by() silently skips non-existing fields on related fields. → QuerySet.order_by() silently skips non-existing fields on related fields with Meta.ordering. |
---|
comment:8 by , 2 years ago
Patch needs improvement: | set |
---|
comment:10 by , 2 years ago
Patch needs improvement: | unset |
---|---|
Triage Stage: | Accepted → Ready for checkin |
Tenatively accepted, I'm not sure it's worth the additional complexity (similar to the #29408, see 440505cb2cadbe1a5b9fba246bcde6c04f51d07e).