If __neg__ is the preferred method of applying ordering then I think we
should prevent __neg__ from being used in the mathematical sense in the
other methods (filter, annotate etc). There hasn't been a need for negating
an expression/F() object before, and negation would only work with certain
expressions anyway (what would -Lower('description') even mean?).
The problem with applying ordering to an expression still applies:
Model.objects.all().order_by( F('field')+F('other') )
Here, it's actually the connector (+) that is the outer-most level, so
there's no opportunity to apply ordering to any of the expressions. I've
found a similar problem with trying to apply an `output_type` to
expressions that are joined by a connector. I think the solution is to
introduce a new type that simply wraps another expression for the purposes
of mutation.
Model.objects.all().order_by( -Wrap(F('field')+F('other')) )
Model.objects.annotate( Wrap(F('field')+5, output_type=IntegerField()) )
But I'd be interested in hearing alternatives.
Josh
On Monday, 9 June 2014 20:01:18 UTC+10, Anssi Kääriäinen wrote:
>
> Using __neg__ for ordering seems like a good approach to me. I don't
> like F('-field') that much, if -F('field') works, then F('-field') is
> duplicate API for the exact same thing.
>
> The only problem with -F('field') is that there might be situations where
> ORDER BY -field ASC gives different results than ORDER BY field DESC. I am
> not sure if any such thing exists (maybe null handling?), but if so, and if
> we also add support for __neq__ for somecol__lt=-F('field'), then users
> might get unexpected results from .order_by(-F('field')). OTOH if we
> document that '-' means DESC ordering when used at outermost level in
> .order_by(), the API is hopefully clear enough.
>
> - Anssi
>
> On 06/09/2014 09:33 AM, Marc Tamlyn wrote:
>
> Agreed. It's worth noting that we could have a `Desc` operator for awkward
> edge cases where __neg__ doesn't work well, and the default implementation
> of __neg__ just returns Desc(self). I've not completely considered all the
> possible implications here, just throwing the idea around.
>
>
> On 9 June 2014 01:53, Josh Smeaton <[email protected] <javascript:>>
> wrote:
>
>> > That sounds like a workable approach. If I'm understanding right,
>> this means putting the ordering flag on the ExpressionNode class so that
>> all nodes will have this whether or not they are to be used in an ordering
>> context?
>>
>> Yes, that had been what I was thinking, based upon the implementation
>> of PeeWee ( https://github.com/coleifer/peewee/blob/master/peewee.py#L292
>> ). At first it doesn't seem very nice; having an expression containing
>> properties regarding ordering or even aggregates (like the current
>> is_aggregate). But in my experience it has turned out to be the nicest
>> place to put that information, that doesn't infect a large number of
>> components. "An expression can be ordered" makes sense.
>>
>> > My only reservation about this when combined with __neg__ is that it
>> means that certain mathematical expressions will behave oddly
>>
>> __neg__ isn't currently supported on expressions, so it has no current
>> meaning. It could be used in the mathematical context though in the future,
>> and would make sense.
>>
>> > I think supporting this gives lots of potential problems without much
>> in the way of gain. Even the "correct" form Coalesce('-title',
>> '-description') just looks odd to me. The DESC modifier applies to the
>> expression as a whole, not to any one field within it
>>
>> Totally agree. Ordering applies to the expression, not any one node
>> within that expression. So we need to figure out how best to support:
>>
>> .order_by( F('field_a')+F('field_b') )
>>
>>
>> You can't apply ordering to field_a or field_b, because the returned
>> Expression is actually `+ (field_a, field_b)`. Considering that, a wrapping
>> `Desc(expression)` probably makes a lot of sense, but has the following
>> problems:
>>
>> 1. The syntax is somewhat ugly, but fits with the theme of composable
>> expressions.
>> 2. If `Desc()` is just another expression, you'd need to prevent it from
>> being used in an `inner` context. It can only be a wrapper. I think
>> documenting this limitation is fine - but if there was a way to throw a
>> useful error (rather than the database error that would surely follow),
>> it'd be nice.
>> 3. order_by(F('-field_a')) wouldn't be possible - there's no way for the
>> `F()` to push the `Desc()` to the top of the tree. Since this isn't already
>> supported anyway, I don't think it's that big of a deal.
>> 4. order_by('-field_a') should produce: Desc(F('field_a')), but I think
>> that'd be very easy. Expressions should be the only supported API for
>> order_by, except a string referencing a field (like it is now) that is
>> internally converted to an Expression. I do the same thing with Aggregates
>> right now.
>>
>> > An alternative is to use ~ instead of - meaning inverse instead of
>> negative. This might be more appropriate (but then is ~LowerCase not
>> UpperCase?).
>>
>> I don't think anyone would ever expect ~LowerCase to mean UpperCase,
>> but it is still somewhat confusing syntax. ~ is mostly used in Q() objects
>> to mean NOT, and could be very confusing. We also run into similar issues
>> with the `order_by( F()+F() )` use case above - applying a unary operator
>> to either of those objects won't actually result in any ordering being
>> applied.
>>
>> Josh
>>
>> On Monday, 9 June 2014 02:07:42 UTC+10, Tim Martin wrote:
>>>
>>>
>>> On Sunday, 8 June 2014 13:24:01 UTC+1, Josh Smeaton wrote:
>>>>
>>>> I've thought about this previously, and what I had in mind was:
>>>>
>>>> - Expressions should support an ordering parameter of some kind in
>>>> the constructor, and save it to an ordering property. Default to ASC
>>>> - If we go with Marc's suggestion, the __neg__ can set the above
>>>> property. This would look very consistent with the existing ordering api.
>>>> - F() objects should parse their field argument, and internally set
>>>> their ordering attribute appropriately -> F('-title') should strip the `-`
>>>> and set a DESC ordering.
>>>> - Since expressions can be nested, you can't return ASC/DESC from the
>>>> as_sql() method, otherwise you'd end up with weirdness like:
>>>> Coalesce(field_a
>>>> ASC, field_b ASC) instead of Coalesce(field_a, field_b) ASC.
>>>> Therefore, the order_by machinery should call a `get_ordering()` (or
>>>> something named similarly) and generate the ASC/DESC token accordingly.
>>>>
>>>
>>> That sounds like a workable approach. If I'm understanding right, this
>>> means putting the ordering flag on the ExpressionNode class so that all
>>> nodes will have this whether or not they are to be used in an ordering
>>> context?
>>>
>>> My only reservation about this when combined with __neg__ is that it
>>> means that certain mathematical expressions will behave oddly. For example,
>>> you might want to do something like
>>>
>>> Accounts.objects.filter(balance__lt=-F('overdraft_limit'))
>>>
>>> but this will end up flipping the ordering rather than doing a
>>> mathematical negative. Is this dealt with by putting logic into the
>>> SQLEvaluator so that it knows whether it's evaluating in an ordering
>>> context or a SELECT or WHERE clause context and does the right thing?
>>>
>>>
>>>> Usage:
>>>>
>>>> Article.objects.order_by(LowerCase('title', ordering='-'))
>>>>
>>>> Article.objects.order_by(-LowerCase('title')) # I prefer this form
>>>>
>>>> Article.objects.order_by('-title') and
>>>> Article.objects.order_by(F('-title')) # should be equivalent (a
>>>> string argument should be converted to an F())
>>>>
>>>>
>>>> I'm unsure whether or not expressions should inspect their "children"
>>>> for an ordering if one isn't supplied in the outer-level:
>>>>
>>>> Article.objects.order_by(LowerCase('-title'))
>>>>
>>>>
>>>> Should the Lowercase try to resolve the ordering of `title` and use
>>>> it as it's own? I don't think so, because it could lead to weird conflicts
>>>> where multiple arguments define different ordering:
>>>>
>>>> Article.objects.order_by(Coalesce('-title', '+description')) # is
>>>> ASC or DESC used? Possibly confusing
>>>>
>>>>
>>>> Thoughts?
>>>>
>>>
>>>
>>> I think supporting this gives lots of potential problems without much in
>>> the way of gain. Even the "correct" form Coalesce('-title',
>>> '-description') just looks odd to me. The DESC modifier applies to the
>>> expression as a whole, not to any one field within it.
>>>
>>> Tim
>>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "Django developers" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to [email protected] <javascript:>.
>> To post to this group, send email to [email protected]
>> <javascript:>.
>> Visit this group at http://groups.google.com/group/django-developers.
>> To view this discussion on the web visit
>> https://groups.google.com/d/msgid/django-developers/6365dba1-2dfc-469d-988b-3cb800cc0f76%40googlegroups.com
>>
>> <https://groups.google.com/d/msgid/django-developers/6365dba1-2dfc-469d-988b-3cb800cc0f76%40googlegroups.com?utm_medium=email&utm_source=footer>.
>>
>>
>>
>> For more options, visit https://groups.google.com/d/optout.
>>
>
> --
> You received this message because you are subscribed to the Google Groups
> "Django developers" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected] <javascript:>.
> To post to this group, send email to [email protected]
> <javascript:>.
> Visit this group at http://groups.google.com/group/django-developers.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-developers/CAMwjO1E36SeDW4R_jQOcw%3DkGV%2BwG5uaE%3D1Vif5DyDgwJY3ikcA%40mail.gmail.com
>
> <https://groups.google.com/d/msgid/django-developers/CAMwjO1E36SeDW4R_jQOcw%3DkGV%2BwG5uaE%3D1Vif5DyDgwJY3ikcA%40mail.gmail.com?utm_medium=email&utm_source=footer>
> .
> For more options, visit https://groups.google.com/d/optout.
>
>
>
--
You received this message because you are subscribed to the Google Groups
"Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-developers/4e8e8101-87d2-4d4a-8c1c-79f885fe5291%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.