@@ -113,15 +113,15 @@ You can easily traverse multiple relationships when filtering by using ``Related
113
113
114
114
115
115
class DepartmentFilter(filters.FilterSet):
116
- manager = filters.RelatedFilter(ManagerFilter, name = ' manager' )
116
+ manager = filters.RelatedFilter(ManagerFilter, name = ' manager' , queryset = Manager.objects.all() )
117
117
118
118
class Meta:
119
119
model = Department
120
120
fields = {' name' : [' exact' , ' in' , ' startswith' ]}
121
121
122
122
123
123
class CompanyFilter(filters.FilterSet):
124
- department = filters.RelatedFilter(DepartmentFilter, name = ' department' )
124
+ department = filters.RelatedFilter(DepartmentFilter, name = ' department' , queryset = Department.objects.all() )
125
125
126
126
class Meta:
127
127
model = Company
@@ -140,13 +140,32 @@ Example filter calls:
140
140
/ api/ companies? department__name=Accounting
141
141
/ api/ companies? department__manager__name__startswith=Bob
142
142
143
+ `` queryset`` callables
144
+ """ """ """ """ """ """ """ "
145
+
146
+ Since ``RelatedFilter`` is a subclass of ``ModelChoiceFilter``, the ``queryset`` argument supports callable behavior.
147
+ In the following example, the set of departments is restricted to those in the user's company.
148
+
149
+ .. code-block:: python
150
+
151
+ def departments(request):
152
+ company = request.user.company
153
+ return company.department_set.all()
154
+
155
+ class EmployeeFilter(filters.FilterSet):
156
+ department = filters.RelatedFilter(filterset=DepartmentFilter, queryset=departments)
157
+ ...
158
+
159
+ Recursive relationships
160
+ """ """ """ """ """ """ """ " "
161
+
143
162
Recursive relations are also supported. It may be necessary to specify the full module path.
144
163
145
164
.. code- block:: python
146
165
147
166
class PersonFilter(filters.FilterSet):
148
167
name = filters.AllLookupsFilter(name = ' name' )
149
- best_friend = filters.RelatedFilter(' people.views.PersonFilter' , name = ' best_friend' )
168
+ best_friend = filters.RelatedFilter(' people.views.PersonFilter' , name = ' best_friend' , queryset = Person.objects.all() )
150
169
151
170
class Meta:
152
171
model = Person
@@ -185,7 +204,7 @@ to all filter classes. It incorporates some of the implementation details of the
185
204
return qs.filter(** {lookup_expr: isnull})
186
205
187
206
class AuthorFilter(filters.FilterSet):
188
- posts = filters.RelatedFilter(' PostFilter' )
207
+ posts = filters.RelatedFilter(' PostFilter' , queryset = Post.objects.all() )
189
208
190
209
class Meta:
191
210
model = Author
@@ -285,15 +304,15 @@ You cannot combine ``AllLookupsFilter`` with ``RelatedFilter`` as the filter nam
285
304
.. code- block:: python
286
305
287
306
class ProductFilter(filters.FilterSet):
288
- manufacturer = filters.RelatedFilter(' ManufacturerFilter' )
307
+ manufacturer = filters.RelatedFilter(' ManufacturerFilter' , queryset = Manufacturer.objects.all() )
289
308
manufacturer = filters.AllLookupsFilter()
290
309
291
310
To work around this, you have the following options:
292
311
293
312
.. code- block:: python
294
313
295
314
class ProductFilter(filters.FilterSet):
296
- manufacturer = filters.RelatedFilter(' ManufacturerFilter' )
315
+ manufacturer = filters.RelatedFilter(' ManufacturerFilter' , queryset = Manufacturer.objects.all() )
297
316
298
317
class Meta:
299
318
model = Product
@@ -304,7 +323,7 @@ To work around this, you have the following options:
304
323
# or
305
324
306
325
class ProductFilter(filters.FilterSet):
307
- manufacturer = filters.RelatedFilter(' ManufacturerFilter' , lookups = ' __all__' ) # `lookups` also accepts a list
326
+ manufacturer = filters.RelatedFilter(' ManufacturerFilter' , queryset = Manufacturer.objects.all(), lookups = ' __all__' ) # `lookups` also accepts a list
308
327
309
328
class Meta:
310
329
model = Product
@@ -326,15 +345,15 @@ and ``FilterSet``s from either package are compatible with the other's DRF backe
326
345
...
327
346
328
347
class DRFFilter(rest_framework_filters.FilterSet):
329
- vanilla = rest_framework_filters.RelatedFilter(filterset = VanillaFilter)
348
+ vanilla = rest_framework_filters.RelatedFilter(filterset = VanillaFilter, queryset = ... )
330
349
331
350
332
351
# invalid
333
352
class DRFFilter(rest_framework_filters.FilterSet):
334
353
...
335
354
336
355
class VanillaFilter(django_filters.FilterSet):
337
- drf = rest_framework_filters.RelatedFilter(filterset = DRFFilter)
356
+ drf = rest_framework_filters.RelatedFilter(filterset = DRFFilter, queryset = ... )
338
357
339
358
340
359
Caveats & Limitations
@@ -380,6 +399,22 @@ The recommended solutions are to either:
380
399
? publish_date__range=2016 - 01 - 01 ,2016 - 02 - 01
381
400
382
401
402
+ Migrating to 1.0
403
+ ----------------
404
+
405
+ `` RelatedFilter.queryset`` now required
406
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
407
+
408
+ The related filterset' s model is no longer used to provide the default value for ``RelatedFilter.queryset``. This
409
+ change reduces the chance of unintentionally exposing data in the rendered filter forms. You must now explicitly
410
+ provide the `` queryset`` argument, or override the `` get_queryset()`` method (see `queryset callables` _).
411
+
412
+
413
+ `` get_filters()`` renamed to `` expand_filters()``
414
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
415
+
416
+ django- filter has add a `` get_filters()`` classmethod to it' s API, so this method has been renamed.
417
+
383
418
License
384
419
------ -
385
420
Copyright (c) 2013 - 2015 Philip Neustrom < philipn@ gmail.com> ,
0 commit comments