group filter fields with meta option 'together'
This commit is contained in:
parent
13d4fe30e5
commit
d3c80b9d34
3
AUTHORS
3
AUTHORS
|
@ -18,4 +18,5 @@ Vladimir Sidorenko
|
|||
Tom Christie
|
||||
Remco Wendt
|
||||
Axel Haustant
|
||||
Brad Erickson
|
||||
Brad Erickson
|
||||
Diogo Laginha
|
|
@ -141,6 +141,8 @@ class FilterSetOptions(object):
|
|||
self.order_by = getattr(options, 'order_by', False)
|
||||
|
||||
self.form = getattr(options, 'form', forms.Form)
|
||||
|
||||
self.together = getattr(options, 'together', None)
|
||||
|
||||
|
||||
class FilterSetMetaclass(type):
|
||||
|
@ -352,6 +354,22 @@ class BaseFilterSet(object):
|
|||
|
||||
@property
|
||||
def form(self):
|
||||
|
||||
def full_clean(form):
|
||||
super(form.__class__, form).full_clean()
|
||||
message = 'Following fields must be together: %s'
|
||||
together = self._meta.together
|
||||
cleaned_data = form.cleaned_data
|
||||
if isinstance(together[0], (list, tuple)):
|
||||
for each in together:
|
||||
count = len([i for i in each if cleaned_data.get(i)])
|
||||
if 0 < count < len(each):
|
||||
return form.add_error(None, message % ','.join(each))
|
||||
else:
|
||||
count = len([i for i in together if cleaned_data.get(i)])
|
||||
if 0 < count < len(together):
|
||||
return form.add_error(None, message % ','.join(together))
|
||||
|
||||
if not hasattr(self, '_form'):
|
||||
fields = OrderedDict([
|
||||
(name, filter_.field)
|
||||
|
@ -359,6 +377,8 @@ class BaseFilterSet(object):
|
|||
fields[self.order_by_field] = self.ordering_field
|
||||
Form = type(str('%sForm' % self.__class__.__name__),
|
||||
(self._meta.form,), fields)
|
||||
if self._meta.together:
|
||||
Form.full_clean = full_clean
|
||||
if self.is_bound:
|
||||
self._form = Form(self.data, prefix=self.form_prefix)
|
||||
else:
|
||||
|
|
|
@ -199,6 +199,24 @@ The inner ``Meta`` class also takes an optional ``form`` argument. This is a
|
|||
form class from which ``FilterSet.form`` will subclass. This works similar to
|
||||
the ``form`` option on a ``ModelAdmin.``
|
||||
|
||||
Group fields with ``together``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The inner ``Meta`` class also takes an optional ``together`` argument. This
|
||||
is a list of lists, each containing field names. For convenience can be a
|
||||
single list/tuple when dealing with a single set of fields. Fields within a
|
||||
field set must either be all or none present in the request for
|
||||
``FilterSet.form`` to be valid.
|
||||
|
||||
import django_filters
|
||||
|
||||
class ProductFilter(django_filters.FilterSet):
|
||||
class Meta:
|
||||
model = Product
|
||||
fields = ['price', 'release_date', 'rating']
|
||||
together = ['rating', 'price']
|
||||
|
||||
|
||||
Non-Meta options
|
||||
----------------
|
||||
|
||||
|
|
2
setup.py
2
setup.py
|
@ -16,7 +16,7 @@ if sys.argv[-1] == 'publish':
|
|||
|
||||
setup(
|
||||
name='django-filter',
|
||||
version='0.9.2',
|
||||
version='0.9.3',
|
||||
description=('Django-filter is a reusable Django application for allowing'
|
||||
' users to filter querysets dynamically.'),
|
||||
long_description=readme,
|
||||
|
|
|
@ -628,3 +628,45 @@ class FilterSetOrderingTests(TestCase):
|
|||
f = F({'o': 'status'}, queryset=self.qs)
|
||||
self.assertQuerysetEqual(
|
||||
f.qs, ['carl', 'alex', 'aaron', 'jacob'], lambda o: o.username)
|
||||
|
||||
|
||||
|
||||
class FilterSetTogetherTests(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.alex = User.objects.create(username='alex', status=1)
|
||||
self.jacob = User.objects.create(username='jacob', status=2)
|
||||
self.qs = User.objects.all().order_by('id')
|
||||
|
||||
def test_fields_set(self):
|
||||
class F(FilterSet):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ['username', 'status', 'is_active', 'first_name']
|
||||
together = [
|
||||
('username', 'status'),
|
||||
('first_name', 'is_active'),
|
||||
]
|
||||
|
||||
f = F({}, queryset=self.qs)
|
||||
self.assertEqual(f.qs.count(), 2)
|
||||
f = F({'username': 'alex'}, queryset=self.qs)
|
||||
self.assertEqual(f.qs.count(), 0)
|
||||
f = F({'username': 'alex', 'status': 1}, queryset=self.qs)
|
||||
self.assertEqual(f.qs.count(), 1)
|
||||
self.assertQuerysetEqual(f.qs, [self.alex.pk], lambda o: o.pk)
|
||||
|
||||
def test_single_fields_set(self):
|
||||
class F(FilterSet):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ['username', 'status']
|
||||
together = ['username', 'status']
|
||||
|
||||
f = F({}, queryset=self.qs)
|
||||
self.assertEqual(f.qs.count(), 2)
|
||||
f = F({'username': 'alex'}, queryset=self.qs)
|
||||
self.assertEqual(f.qs.count(), 0)
|
||||
f = F({'username': 'alex', 'status': 1}, queryset=self.qs)
|
||||
self.assertEqual(f.qs.count(), 1)
|
||||
self.assertQuerysetEqual(f.qs, [self.alex.pk], lambda o: o.pk)
|
||||
|
|
Loading…
Reference in New Issue