[Django] #26225: Coalesce Multiple Calls to order_by with Same Arguments

9 views
Skip to first unread message

Django

unread,
Feb 16, 2016, 11:24:13 AM2/16/16
to django-...@googlegroups.com
#26225: Coalesce Multiple Calls to order_by with Same Arguments
-------------------------------+--------------------
Reporter: cancan101 | Owner: nobody
Type: Uncategorized | Status: new
Component: Uncategorized | Version: 1.9
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------
Currently multiple calls to `order_by` with the same arguments will
invalidate the query cache. While the
[https://docs.djangoproject.com/en/stable/ref/models/querysets/ the
documentation] notes, "Each `order_by()` call will clear any previous
ordering" (it returns a new `QuerySet`), I see no reason to clear the
cache / not return `self` in the case of calling `order_by` with the
currently sort order.

Here is an example in action:
{{{
>>> children = Child.objects.order_by('saved_dt').all()
>>> list(children)
[<Child: Child object>, <Child: Child object>]
(0.001) SELECT "prefetch_child"."id", "prefetch_child"."saved_dt",
"prefetch_child"."parent_id" FROM "prefetch_child" ORDER BY
"prefetch_child"."saved_dt" ASC; args=()
>>> list(children)
[<Child: Child object>, <Child: Child object>]
>>> children.order_by('saved_dt')
[<Child: Child object>, <Child: Child object>]
(0.000) SELECT "prefetch_child"."id", "prefetch_child"."saved_dt",
"prefetch_child"."parent_id" FROM "prefetch_child" ORDER BY
"prefetch_child"."saved_dt" ASC LIMIT 21; args=()
}}}

I would hope that the second call to `children.order_by('saved_dt')` can
return self since the queryset is already sorted by the desired key.

This is related to ticket: https://code.djangoproject.com/ticket/26211

--
Ticket URL: <https://code.djangoproject.com/ticket/26225>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Feb 16, 2016, 2:40:21 PM2/16/16
to django-...@googlegroups.com
#26225: Coalesce Multiple Calls to order_by with Same Arguments
-------------------------------------+-------------------------------------
Reporter: cancan101 | Owner: nobody
Type: | Status: new
Cleanup/optimization |
Component: Database layer | Version: 1.9
(models, ORM) |
Severity: Normal | Resolution:
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 timgraham):

* cc: akaariai, mjtamlyn, jarshwah (added)
* needs_better_patch: => 0
* component: Uncategorized => Database layer (models, ORM)
* needs_tests: => 0
* needs_docs: => 0
* type: Uncategorized => Cleanup/optimization


Comment:

I'm a bit nervous this change might cause subtle backwards
incompatibilities in case someone is relying on a redundant `order_by()`
to reevaluate the queryset. I wonder if you can make your reasoning any
more persuasive than "I see no reason against it." The reasons against it
I see:
1. additional complexity
2. inconsistency with other queyset methods (e.g. should any of them also
try to detect if they are applied redundantly?)

I'll leave it open for opinions from ORM experts.

--
Ticket URL: <https://code.djangoproject.com/ticket/26225#comment:1>

Django

unread,
Feb 17, 2016, 4:28:49 AM2/17/16
to django-...@googlegroups.com
#26225: Coalesce Multiple Calls to order_by with Same Arguments
-------------------------------------+-------------------------------------
Reporter: cancan101 | Owner: nobody

Type: | Status: new
Cleanup/optimization |
Component: Database layer | Version: 1.9
(models, ORM) |
Severity: Normal | Resolution:
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 mjtamlyn):

Yes, this would make significant unnecessary complexity in my opinion. The
ORM currently abides by a simple rule that chaining on another call
creates a new queryset. We even explicitly use this with `all()` in
`forms.ModelChoiceField` - and that's an API which can ''never'' change
the queryset.

It's worth noting that you could add this kind of behaviour to a custom
queryset class, but you would be inspecting private properties of the
underlying query object to get what you want. Looking at the original
ticket you opened, how I would approach that sort of situation where a you
have code which may have a prefetched query or may not is to use `to_attr`
- prefetch to `_ordered_children` and then have a `ordered_children`
method which returns `_ordered_children` if it exists, or runs the query
if not.

--
Ticket URL: <https://code.djangoproject.com/ticket/26225#comment:2>

Django

unread,
Feb 17, 2016, 7:12:40 AM2/17/16
to django-...@googlegroups.com
#26225: Coalesce Multiple Calls to order_by with Same Arguments
-------------------------------------+-------------------------------------
Reporter: cancan101 | Owner: nobody

Type: | Status: new
Cleanup/optimization |
Component: Database layer | Version: 1.9
(models, ORM) |
Severity: Normal | Resolution:
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 jarshwah):

I agree with Marc. Too complex for very little gain. Imagine the case
where you have multiple complex ordering expressions:

{{{
qs.order_by(Upper('field_a').asc(), Lower('field_b').desc(),
Concat(F('field_c'), F('field_d')).asc())
}}}

If another ordering queryset method is applied, to determine if that was
"the same" as last time, you could only really do identity checks which
fails unless the objects are reused, or to generate what the ordering sql
would be, and comparing that against the existing. Neither of those
options are fool proof, and generating the sql would be fairly expensive
for very little gain.

--
Ticket URL: <https://code.djangoproject.com/ticket/26225#comment:3>

Django

unread,
Feb 17, 2016, 7:25:42 AM2/17/16
to django-...@googlegroups.com
#26225: Coalesce Multiple Calls to order_by with Same Arguments
-------------------------------------+-------------------------------------
Reporter: cancan101 | Owner: nobody
Type: | Status: closed

Cleanup/optimization |
Component: Database layer | Version: 1.9
(models, ORM) |
Severity: Normal | Resolution: wontfix
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 mjtamlyn):

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


--
Ticket URL: <https://code.djangoproject.com/ticket/26225#comment:4>

Django

unread,
Feb 17, 2016, 2:35:32 PM2/17/16
to django-...@googlegroups.com
#26225: Coalesce Multiple Calls to order_by with Same Arguments
-------------------------------------+-------------------------------------
Reporter: cancan101 | Owner: nobody

Type: | Status: closed
Cleanup/optimization |
Component: Database layer | Version: 1.9
(models, ORM) |
Severity: Normal | Resolution: wontfix
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 shaib):

* cc: shaib (added)


Comment:

Replying to [comment:2 mjtamlyn]:
> [Y]ou could add this kind of behaviour to a custom queryset class, but


you would be inspecting private properties of the underlying query object
to get what you want.

Perhaps we should consider making such properties public? It could help
with making querysets more composable and reusable, I think.

--
Ticket URL: <https://code.djangoproject.com/ticket/26225#comment:5>

Django

unread,
Feb 17, 2016, 2:37:43 PM2/17/16
to django-...@googlegroups.com
#26225: Coalesce Multiple Calls to order_by with Same Arguments
-------------------------------------+-------------------------------------
Reporter: cancan101 | Owner: nobody

Type: | Status: closed
Cleanup/optimization |
Component: Database layer | Version: 1.9
(models, ORM) |
Severity: Normal | Resolution: wontfix
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 cancan101):

Replying to [comment:5 shaib]:

Related might be this SO post which is incorrectly answered:
http://stackoverflow.com/questions/18835961/django-how-to-find-which-
fields-a-queryset-is-being-ordered-by/18852765

--
Ticket URL: <https://code.djangoproject.com/ticket/26225#comment:6>

Reply all
Reply to author
Forward
0 new messages