Skip to content

Commit 097828a

Browse files
author
Ryan P Kilby
committed
Use filters_for_model to create all/related looups
1 parent ffc1a2a commit 097828a

File tree

2 files changed

+42
-32
lines changed

2 files changed

+42
-32
lines changed

rest_framework_filters/filterset.py

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import warnings
77

88
from django.db.models.constants import LOOKUP_SEP
9-
from django.db.models.fields.related import ForeignObjectRel
109
from django.utils import six
1110

1211
from django_filters import filterset, rest_framework
@@ -51,38 +50,37 @@ def __new__(cls, name, bases, attrs):
5150
if not opts.model:
5251
return new_class
5352

54-
# Populate our FilterSet fields with all the possible
55-
# filters for the AllLookupsFilter field.
53+
# Determine declared filters and filters to generate lookups from. Declared
54+
# filters have precedence over generated filters and should not be overwritten.
55+
declared_filters, lookups_filters = OrderedDict(), OrderedDict()
56+
for name, f in six.iteritems(new_class.declared_filters):
57+
if isinstance(f, (filters.AllLookupsFilter, filters.RelatedFilter)):
58+
lookups_filters[name] = f
59+
60+
# `AllLookupsFilter` is an exception, as it should be overwritten
61+
if not isinstance(f, filters.AllLookupsFilter):
62+
declared_filters[name] = f
63+
64+
# generate filters for AllLookups/Related filters
65+
# name is the parameter name on the filterset, f.name is the model field's name
66+
opts = copy.deepcopy(opts)
67+
for name, f in six.iteritems(lookups_filters):
68+
opts.fields = {f.name: f.lookups or []}
69+
new_filters = new_class.filters_for_model(opts.model, opts)
70+
71+
# filters_for_model generate param names from the model field name
72+
# replace model field name with the parameter name from the filerset
73+
new_class.base_filters.update(OrderedDict(
74+
(param.replace(f.name, name, 1), v)
75+
for param, v in six.iteritems(new_filters)
76+
))
77+
78+
# re-apply declared filters (sans `AllLookupsFilter`s)
79+
new_class.base_filters.update(declared_filters)
80+
81+
# TODO: remove with deprecations
5682
for name, filter_ in six.iteritems(new_class.base_filters.copy()):
57-
if isinstance(filter_, (filters.AllLookupsFilter, filters.RelatedFilter)):
58-
field = filterset.get_model_field(opts.model, filter_.name)
59-
60-
lookups = filter_.lookups or []
61-
if lookups == '__all__':
62-
lookups = utils.lookups_for_field(field)
63-
64-
for lookup_expr in lookups:
65-
if isinstance(filter_, filters.RelatedFilter) and lookup_expr == 'exact':
66-
# Don't replace the RelatedFilter
67-
continue
68-
69-
if isinstance(field, ForeignObjectRel):
70-
f = new_class.filter_for_reverse_field(field, filter_.name)
71-
else:
72-
f = new_class.filter_for_field(field, filter_.name, lookup_expr)
73-
f = fix_filter_field(f)
74-
75-
# compute filter name
76-
filter_name = LOOKUP_SEP.join([name, lookup_expr])
77-
78-
# Don't add "exact" to filter names
79-
_exact = LOOKUP_SEP + 'exact'
80-
if filter_name.endswith(_exact):
81-
filter_name = filter_name[:-len(_exact)]
82-
83-
new_class.base_filters[filter_name] = f
84-
85-
elif name not in new_class.declared_filters:
83+
if name not in new_class.declared_filters:
8684
new_class.base_filters[name] = fix_filter_field(filter_)
8785

8886
return new_class

tests/test_filterset.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@ class LookupsFilterTests(TestCase):
2828
Test basic filter construction for `AllLookupsFilter`, '__all__', and `RelatedFilter.lookups`.
2929
"""
3030

31+
def test_alllookupsfilter_meta_fields_unmodified(self):
32+
f = []
33+
34+
class F(FilterSet):
35+
id = filters.AllLookupsFilter()
36+
37+
class Meta:
38+
model = Note
39+
fields = f
40+
41+
self.assertIs(F._meta.fields, f)
42+
3143
def test_alllookupsfilter_replaced(self):
3244
# See: https://github.com/philipn/django-rest-framework-filters/issues/118
3345
class F(FilterSet):

0 commit comments

Comments
 (0)