The parens definitely would work for __neg__, and as for the output_type 
problem, it's only an issue when mixing field types - but that can be 
solved by applying a matching output_type to one of the inner expressions. 
If a wrapping type isn't needed for neg, I won't introduce one to slightly 
improve the aesthetics of combinable expressions.

To answer your question about using F() as a wrapper - no that wouldn't 
work. F() must refer to an existing field by name - it doesn't wrap 
expressions.

Josh

On Monday, 9 June 2014 20:34:04 UTC+10, Anssi Kääriäinen wrote:
>
>  Could we use just F() for this, that is the examples would be:
> -F(F('field')+F('other'))
> F(F('field')+5, output_type=IntegerField())
>
> As Marc said in another post plain parentheses should be enough for the 
> first case.
>
>  - Anssi
>
> On 06/09/2014 01:19 PM, Josh Smeaton wrote:
>  
> 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]> 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].
>>> 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/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].
>> 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/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] <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/4e8e8101-87d2-4d4a-8c1c-79f885fe5291%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/django-developers/4e8e8101-87d2-4d4a-8c1c-79f885fe5291%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].
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/18d0d818-5ae2-4087-9726-9b9cfa2ce3b1%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to