Skip to content

Commit 236d11a

Browse files
author
Ryan P Kilby
committed
Add MethodFilter documentation
1 parent c1a48d5 commit 236d11a

File tree

1 file changed

+54
-2
lines changed

1 file changed

+54
-2
lines changed

README.rst

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ then we can filter like so::
165165
/api/page/?author__username__icontains=john
166166

167167
Automatic Filter Negation/Exclusion
168-
~~~~~~~~~~~~~~~~~~~~~~~~~
168+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
169169

170170
FilterSets also support automatic exclusion using a simple ``k!=v`` syntax. This syntax
171171
internally sets the ``exclude`` property on the filter.
@@ -178,8 +178,60 @@ excluding those containing "World".
178178

179179
/api/articles/?title__contains=Hello&title__contains!=World
180180

181+
MethodFilter Reimplementation
182+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
183+
184+
``MethodFilter`` has been reimplemented to work across relationships. This is not a
185+
forwards-compatible change and requires adding a minimal amount of boilerplate to the
186+
filter method.
187+
188+
When filtering across relationships, the queryset and lookup value will be different.
189+
For example:
190+
191+
class PostFilter(filters.FilterSet):
192+
author = filters.RelatedFilter('AuthorFilter')
193+
is_published = filters.MethodFilter()
194+
195+
class Meta:
196+
model = Post
197+
fields = ['title', 'content']
198+
199+
def filter_is_published(self, name, qs, value):
200+
# convert value to boolean
201+
null = value.lower() != 'true'
202+
203+
# The lookup name will end with `is_published`, but could be
204+
# preceded by a related lookup path.
205+
if LOOKUP_SEP in name:
206+
rel, _ = name.rsplit(LOOKUP_SEP, 1)
207+
name = LOOKUP_SEP.join([rel, 'date_published__isnull'])
208+
else:
209+
name = 'date_published__isnull'
210+
211+
return qs.filter(**{name: null})
212+
213+
class AuthorFilter(filters.FilterSet):
214+
posts = filters.RelatedFilter('PostFilter')
215+
216+
class Meta:
217+
model = Author
218+
fields = ['name']
219+
220+
And given these API calls:
221+
222+
/api/posts/?is_published=true
223+
224+
/api/authors/?posts__is_published=true
225+
226+
227+
In the first API call, the filter method receives a queryset of posts. In the second,
228+
it receives a queryset of users. The filter method in the example modifies the lookup
229+
name to work across the relationship, allowing you to find published posts, or authors
230+
who have published posts.
231+
232+
181233
DjangoFilterBackend
182-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
234+
~~~~~~~~~~~~~~~~~~~
183235

184236
We implement our own subclass of ``DjangoFilterBackend``, which you should probably use instead
185237
of the default ``DjangoFilterBackend``. Our ``DjangoFilterBackend`` caches repeated filter set

0 commit comments

Comments
 (0)