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.

Reply via email to