-
Notifications
You must be signed in to change notification settings - Fork 755
/
filterset.txt
220 lines (158 loc) · 6.99 KB
/
filterset.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
=================
FilterSet Options
=================
This document provides a guide on using additional FilterSet features.
Meta options
------------
- :ref:`model <model>`
- :ref:`fields <fields>`
- :ref:`exclude <exclude>`
- :ref:`form <form>`
- :ref:`filter_overrides <filter_overrides>`
.. _model:
Automatic filter generation with ``model``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``FilterSet`` is capable of automatically generating filters for a given
``model``'s fields. Similar to Django's ``ModelForm``, filters are created
based on the underlying model field's type. This option must be combined with
either the ``fields`` or ``exclude`` option, which is the same requirement for
Django's ``ModelForm`` class, detailed `here`__.
__ https://docs.djangoproject.com/en/stable/topics/forms/modelforms/#selecting-the-fields-to-use
.. code-block:: python
class UserFilter(django_filters.FilterSet):
class Meta:
model = User
fields = ['username', 'last_login']
.. _fields:
Declaring filterable ``fields``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``fields`` option is combined with ``model`` to automatically generate
filters. Note that generated filters will not overwrite filters declared on
the ``FilterSet``. The ``fields`` option accepts two syntaxes:
* a list of field names
* a dictionary of field names mapped to a list of lookups
.. code-block:: python
class UserFilter(django_filters.FilterSet):
class Meta:
model = User
fields = ['username', 'last_login']
# or
class UserFilter(django_filters.FilterSet):
class Meta:
model = User
fields = {
'username': ['exact', 'contains'],
'last_login': ['exact', 'year__gt'],
}
The list syntax will create an ``exact`` lookup filter for each field included
in ``fields``. The dictionary syntax will create a filter for each lookup
expression declared for its corresponding model field. These expressions may
include both transforms and lookups, as detailed in the `lookup reference`__.
__ https://docs.djangoproject.com/en/stable/ref/models/lookups/#module-django.db.models.lookups
Note that it is **not** necessary to include declared filters in a ``fields``
list - doing so will only affect the order in which fields appear on a FilterSet's form. Including declarative aliases in a
``fields`` dict will raise an error.
.. code-block:: python
class UserFilter(django_filters.FilterSet):
username = filters.CharFilter()
login_timestamp = filters.IsoDateTimeFilter(field_name='last_login')
class Meta:
model = User
fields = {
'username': ['exact', 'contains'],
'login_timestamp': ['exact'],
}
TypeError("'Meta.fields' contains fields that are not defined on this FilterSet: login_timestamp")
.. _exclude:
Disable filter fields with ``exclude``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``exclude`` option accepts a blacklist of field names to exclude from
automatic filter generation. Note that this option will not disable filters
declared directly on the ``FilterSet``.
.. code-block:: python
class UserFilter(django_filters.FilterSet):
class Meta:
model = User
exclude = ['password']
.. _form:
Custom Forms using ``form``
~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.``
.. _filter_overrides:
Customise filter generation with ``filter_overrides``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The inner ``Meta`` class also takes an optional ``filter_overrides`` argument.
This is a map of model fields to filter classes with options::
class ProductFilter(django_filters.FilterSet):
class Meta:
model = Product
fields = ['name', 'release_date']
filter_overrides = {
models.CharField: {
'filter_class': django_filters.CharFilter,
'extra': lambda f: {
'lookup_expr': 'icontains',
},
},
models.BooleanField: {
'filter_class': django_filters.BooleanFilter,
'extra': lambda f: {
'widget': forms.CheckboxInput,
},
},
}
Overriding ``FilterSet`` methods
--------------------------------
When overriding classmethods, calling ``super(MyFilterSet, cls)`` may result
in a ``NameError`` exception. This is due to the ``FilterSetMetaclass`` calling
these classmethods before the ``FilterSet`` class has been fully created.
There are two recommmended workarounds:
1. If using python 3.6 or newer, use the argumentless ``super()`` syntax.
2. For older versions of python, use an intermediate class. Ex::
class Intermediate(django_filters.FilterSet):
@classmethod
def method(cls, arg):
super(Intermediate, cls).method(arg)
...
class ProductFilter(Intermediate):
class Meta:
model = Product
fields = ['...']
``filter_for_lookup()``
~~~~~~~~~~~~~~~~~~~~~~~
Prior to version 0.13.0, filter generation did not take into account the
``lookup_expr`` used. This commonly caused malformed filters to be generated
for 'isnull', 'in', and 'range' lookups (as well as transformed lookups). The
current implementation provides the following behavior:
- 'isnull' lookups return a ``BooleanFilter``
- 'in' lookups return a filter derived from the CSV-based ``BaseInFilter``.
- 'range' lookups return a filter derived from the CSV-based ``BaseRangeFilter``.
If you want to override the ``filter_class`` and ``params`` used to instantiate
filters for a model field, you can override ``filter_for_lookup()``. Ex::
class ProductFilter(django_filters.FilterSet):
class Meta:
model = Product
fields = {
'release_date': ['exact', 'range'],
}
@classmethod
def filter_for_lookup(cls, f, lookup_type):
# override date range lookups
if isinstance(f, models.DateField) and lookup_type == 'range':
return django_filters.DateRangeFilter, {}
# use default behavior otherwise
return super().filter_for_lookup(f, lookup_type)
.. _filterset_factory:
Using ``filterset_factory``
---------------------------
A ``FilterSet`` for a ``model`` can also be created by the
``filterset_factory``, which creats a ``FilterSet`` with the ``model`` set in
the FilterSets Meta. You can pass a customized ``FilterSet`` class to the
``filterset_factory``, which then uses this class a a base for the created
``FilterSet``. Ex::
class CustomFilterSet(django_filters.FilterSet):
class Meta:
form = CustomFilterSetForm
filterset = filterset_factory(Product, filterset=CustomFilterSet)