> 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 django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
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.
For more options, visit https://groups.google.com/d/optout.

Reply via email to