Belmin Fernandez
Belmin Fernandez

Reputation: 8647

Most efficient way to sort a Django QuerySet based on a form value

Working on a project with another fella. This is some code I wrote in view.py to sort a QuerySet based on some form data:

# Get sort by value
sort_by = search_form.cleaned_data.get('sort_by', SORT_BY_LAST_VISIT)

# Gather stops
stops = Stops.approved_objects.filter(**query_attributes)

# Do neccessary sorting
if sort_by == SORT_BY_PRICE:
    stops = stops.order_by('price')
else: # By default, sort by last visted
    stops = stops.order_by('last_visited')

However, last night my colleague modified the code to this:

# Get sort by value
sort_by = search_form.cleaned_data.get('sort_by', SORT_BY_LAST_VISIT)

# Gather stops based on sort
if sort_by == SORT_BY_PRICE:
    stops = Stops.approved_objects.filter(**query_attributes).order_by('price')
else: # By default, sort by last visted
    stops = Stops.approved_objects.filter(**query_attributes).order_by('last_visited')

His SVN comment: More efficient.

According to Django's documentation, both will equate to one database query. It is possible that I'm missing something else. Perhaps the fact that I'm setting the stops variable (stops = ...) twice?

Because I cannot get a hold of him till Monday, thought I'll go to the SO community on this one.

Upvotes: 0

Views: 429

Answers (2)

aaronasterling
aaronasterling

Reputation: 71004

Your colleague's solution should only save one STORE_FAST instruction (assuming that this is in a function. If it's global than it's a STORE_GLOBAL) and one LOAD_FAST (or LOAD_GLOBAL instruction).

I'm pretty militant about sweating the microseconds (when I know how to) but not at the cost of readability. Your version is much more readable.

Although, I would do

sort_field = 'price' if sort_by == SORT_BY_PRICE else 'last_visited'
stops = Stops.approved_objects.filter(**query_attributes).order_by(sort_field)`

Upvotes: 1

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798656

Unnecessary optimization. Besides:

# settings.py
SORTS = {SORT_BY_PRICE: 'price'}
DEFAULT_SORT = 'last_visited'

# whatever.py
sort_field = settings.SORTS.get(sort_by, settings.DEFAULT_SORT)

stops = Stops.approved_objects.filter(**query_attributes).order_by(sort_field)

That's what you should be doing ;)

Upvotes: 1

Related Questions