Skip to content

Commit

Permalink
Merge branch 'develop' into nicholasserra-bug/descending-order-by
Browse files Browse the repository at this point in the history
  • Loading branch information
apollo13 committed Aug 10, 2013
2 parents 1c21198 + 6e28c45 commit 033a523
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 10 deletions.
23 changes: 15 additions & 8 deletions django_filters/filterset.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from copy import deepcopy

from django import forms
from django.core.validators import EMPTY_VALUES
from django.db import models
from django.db.models.fields import FieldDoesNotExist
from django.db.models.related import RelatedObject
Expand Down Expand Up @@ -264,7 +265,6 @@ def qs(self):

# start with all the results and filter from there
qs = self.queryset.all()
ordered_value = None
for name, filter_ in six.iteritems(self.filters):
value = None
if valid:
Expand All @@ -285,16 +285,20 @@ def qs(self):
if value is not None: # valid & clean data
qs = filter_.filter(qs, value)

# check if we are ordering and if this field is the order_by field
# In the future, maybe collect multiple order_by fields in a dict???
if self._meta.order_by and name == self.order_by_field:
ordered_value = value

if self._meta.order_by:
if ordered_value is None:
order_field = self.form.fields[self.order_by_field]
data = self.form[self.order_by_field].data
ordered_value = None
try:
ordered_value = order_field.clean(data)
except forms.ValidationError:
pass

if ordered_value in EMPTY_VALUES and self.strict:
ordered_value = self.form.fields[self.order_by_field].choices[0][0]

qs = qs.order_by(ordered_value)
if ordered_value:
qs = qs.order_by(*self.get_order_by(ordered_value))

self._qs = qs

Expand Down Expand Up @@ -345,6 +349,9 @@ def ordering_field(self):
self._ordering_field = self.get_ordering_field()
return self._ordering_field

def get_order_by(self, order_choice):
return [order_choice]

@classmethod
def filter_for_field(cls, f, name):
filter_for_field = dict(FILTER_FOR_DBFIELD_DEFAULTS)
Expand Down
18 changes: 18 additions & 0 deletions docs/usage.txt
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,24 @@ If you want to use a custom widget, or in any other way override the ordering
field you can override the ``get_ordering_field()`` method on a ``FilterSet``.
This method just needs to return a Form Field.

Ordering on multiple fields, or other complex orderings can be achieved by
overriding the ``Filterset.get_order_by()`` method. This is passed the selected
``order_by`` value, and is expected to return an iterable of values to pass to
``QuerySet.order_by``. For example, to sort a ``User`` table by last name, then
first name::

class UserFilter(django_filters.FilterSet):
class Meta:
order_by = (
('username', 'Username'),
('last_name', 'Last Name')
)

def get_order_by(self, order_value):
if order_value == 'last_name':
return ['last_name', 'first_name']
return super(UserFilter, self).get_order_by(order_value)

Generic View
------------

Expand Down
34 changes: 32 additions & 2 deletions tests/test_filterset.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,11 @@ class F(FilterSet):
class Meta:
model = User
fields = ['username', 'status']
order_by = ['status']
order_by = ['username', 'status']

f = F({'o': 'username'}, queryset=self.qs)
self.assertQuerysetEqual(
f.qs, ['aaron', 'alex', 'carl', 'jacob'], lambda o: o.username)

f = F({'o': 'status'}, queryset=self.qs)
self.assertQuerysetEqual(
Expand Down Expand Up @@ -481,7 +485,7 @@ class Meta:

f = F({'o': 'username'}, queryset=self.qs)
self.assertQuerysetEqual(
f.qs, ['carl', 'alex', 'jacob', 'aaron'], lambda o: o.username)
f.qs, ['alex', 'jacob', 'aaron', 'carl'], lambda o: o.username)

def test_ordering_on_different_field(self):
class F(FilterSet):
Expand All @@ -494,6 +498,10 @@ class Meta:
self.assertQuerysetEqual(
f.qs, ['aaron', 'alex', 'carl', 'jacob'], lambda o: o.username)

f = F({'o': 'status'}, queryset=self.qs)
self.assertQuerysetEqual(
f.qs, ['carl', 'alex', 'jacob', 'aaron'], lambda o: o.username)

@unittest.skip('todo')
def test_ordering_uses_filter_name(self):
class F(FilterSet):
Expand Down Expand Up @@ -547,3 +555,25 @@ class Meta:
f = F({'o': '-username'}, queryset=self.qs)
self.assertQuerysetEqual(
f.qs, ['jacob', 'carl', 'alex', 'aaron'], lambda o: o.username)

def test_custom_ordering(self):

class F(FilterSet):
debug = True
class Meta:
model = User
fields = ['username', 'status']
order_by = ['username', 'status']

def get_order_by(self, order_choice):
if order_choice == 'status':
return ['status', 'username']
return super(F, self).get_order_by(order_choice)

f = F({'o': 'username'}, queryset=self.qs)
self.assertQuerysetEqual(
f.qs, ['aaron', 'alex', 'carl', 'jacob'], lambda o: o.username)

f = F({'o': 'status'}, queryset=self.qs)
self.assertQuerysetEqual(
f.qs, ['carl', 'alex', 'aaron', 'jacob'], lambda o: o.username)

0 comments on commit 033a523

Please sign in to comment.