On 28 helmi, 01:34, Wim Feijen <[email protected]> wrote:
> Hi all,
>
> We struggled to get a proper definition for a first() and last() method vs.
> earliest() and latest() . I'd like to make one proposal. After that, I
> really like your opinion on which syntax you prefer.
>
> First, let me give you a lenghty introduction. We discussed several use
> cases on this mailing 
> list<https://groups.google.com/forum/?fromgroups=#!searchin/django-develop...>.
> Then, I realized that:
>
> .filter(last_name__startswith='b').order_by('last_name').first()
> is an acceptable compromise for me to use in stead of:
> .first(last_name__startswith='b').order_by('last_name')
>
> Last weekend Aymeric explained to me that earliest can actually accomplish
> the same:
> .filter(last_name__startswith='b').earliest('last_name')
>
> Then, I find "earliest" an inappropriate name, because it does not describe
> functioning well.
>
> Therefore, my proposal is, if we are going to implement the earliest and
> latest method, we should definitely rename them to: first and latest.
>
> After that, there is only one question left:
>
> Which style do you prefer?
>
> .filter(last_name__startswith='b').order_by('last_name').first()    # clear
> and long
> .first(last_name__startswith='b').order_by('last_name')    # first method
> has filter syntax.
> .filter(last_name__startswith='b').first('last_name')   # first method has
> order_by syntax.
>
> So, what do you think?

While investigating the queryset iterator memory leak issue I spotted
some instances of this anti-pattern:
if qs:
    obj = qs[0]
else:
    obj = ...
This has the side effect of fetching the whole dataset into memory
(except on Oracle).

.get() doesn't work for this use-case as multiple objects returned
will cause an error. One solution is:
qs = qs[0:1]
if qs:
    obj = qs[0]
else:
    obj = ...
but this isn't exactly clean.

It would be nice if one could write:
    obj = qs.first() or ...
this is clean and short. (Or equivalently: obj = qs.first(); if not
obj: obj = ...).

I propose the following solution: deprecate earliest()/latest() and
replace them by first()/last(). When using first()/last() no match
isn't an exception, instead None is returned. The method returns the
first/last object by:
  1) the given by_fields
  2) if no by_fields, then Meta.ordering (for earliest/latest this was
by Meta.get_latest_by)
  3) raise error (similar to earilest/latest() - another option would
be implicit ordering by pk, but explicit is better...).

The underlying problem is that there is no simple way to return the
first object of the queryset in a way that multiple or no objects
matched isn't an exception. So, users are either going to write code
using the above mentioned antipattern or forced to use exceptions for
logic.

 - Anssi

-- 
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?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to