For this example:
Model.objects.all().order_by( -Wrap(F('field')+F('other')) )does just the brackets not work? -(f + g) should do f + g (returning some object) and then negate the result. This doesn't solve your output type issue. If it doesn't python's wrong ;) Marc On 9 June 2014 11:19, Josh Smeaton <[email protected]> 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]. > 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 > <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/CAMwjO1HQw5orU7DUpc0Knnimx%2BPm1-sePomF85NZ5y%2BZg4YOWw%40mail.gmail.com. For more options, visit https://groups.google.com/d/optout.
