Opened 4 months ago
Last modified 8 hours ago
#36644 assigned New feature
Enable using an empty order_by() to disable implicit primary key ordering in first()
| Reported by: | Lily | Owned by: | Nilesh Pahari |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | dev |
| Severity: | Normal | Keywords: | |
| Cc: | Jake Howard | 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
As discussed in https://github.com/django/new-features/issues/71, update the interaction between order_by and first to enable this behaviour:
# Existing
MyModel.objects.first() # first, ordered by `pk`
MyModel.objects.order_by("pk").first() # as above
MyModel.objects.order_by("name").first() # first, ordered by `name`
# New
MyModel.objects.order_by().first() # first, but in whatever order the database returns it
This will interact with default orderings (`Meta.ordering`), which will need some careful handling.
Change History (10)
comment:1 by , 4 months ago
| Triage Stage: | Unreviewed → Accepted |
|---|
comment:2 by , 4 months ago
| Owner: | set to |
|---|---|
| Status: | new → assigned |
comment:3 by , 4 months ago
| Cc: | added |
|---|
comment:4 by , 7 weeks ago
| Owner: | changed from to |
|---|
comment:5 by , 7 weeks ago
Just to confirm -- this ticket implements the deprecation step by adding a 'RemovedInDjango70Warning' , and the actual behavior change (disabling the implicit pk ordering) is intended for Django 7.0. Please let me know if I’m missing anything.
comment:6 by , 6 weeks ago
PR: https://github.com/django/django/pull/20458 (added deprecation warning)
comment:7 by , 6 weeks ago
| Has patch: | set |
|---|
comment:8 by , 9 days ago
| Needs documentation: | set |
|---|---|
| Needs tests: | set |
comment:9 by , 13 hours ago
| Needs tests: | unset |
|---|
comment:10 by , 8 hours ago
| Needs documentation: | unset |
|---|---|
| Triage Stage: | Accepted → Ready for checkin |
Update: the union() stuff mentioned above turned out to be a symptom of a separate bug:
Default orderings weren't applied after a union(), due to the particular way that clear_ordering(force=True, clear_default=False) doesn't actually reset QuerySet.default_ordering back to True; it must be done manually. (A call to order_by() with no args does that manually.)
I segregated out Nilesh's fix for the union() behavior into a separate commit.
Then, we were able to do the primary fix for the order_by() <--> first() interaction without any unexpected behavior changes.
For folks checking the forum thread, when Tom Carrick summarized the options discussed here, this was "option 2", to which I did not see specific objections afterward.
I think that looks like this:
django/db/models/query.py
tests/queries/test_qs_combinators.py
first(), a1)I think this will need a deprecation (notice the edited test). We will be enforcing some more explicitness for users who must to clear an ordering for the sake of doing a union but then need to add it back to retain the prior behavior of
first(), but I think that trade-off is worth it.