-
Notifications
You must be signed in to change notification settings - Fork 765
/
backends.py
165 lines (136 loc) · 5.61 KB
/
backends.py
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
import warnings
from django.template import loader
from .. import compat, utils
from . import filters, filterset
class DjangoFilterBackend:
filterset_base = filterset.FilterSet
raise_exception = True
@property
def template(self):
if compat.is_crispy():
return "django_filters/rest_framework/crispy_form.html"
return "django_filters/rest_framework/form.html"
def get_filterset(self, request, queryset, view):
filterset_class = self.get_filterset_class(view, queryset)
if filterset_class is None:
return None
kwargs = self.get_filterset_kwargs(request, queryset, view)
return filterset_class(**kwargs)
def get_filterset_class(self, view, queryset=None):
"""
Return the `FilterSet` class used to filter the queryset.
"""
filterset_class = getattr(view, "filterset_class", None)
filterset_fields = getattr(view, "filterset_fields", None)
if filterset_class:
filterset_model = filterset_class._meta.model
# FilterSets do not need to specify a Meta class
if filterset_model and queryset is not None:
assert issubclass(
queryset.model, filterset_model
), "FilterSet model %s does not match queryset model %s" % (
filterset_model,
queryset.model,
)
return filterset_class
if filterset_fields and queryset is not None:
MetaBase = getattr(self.filterset_base, "Meta", object)
class AutoFilterSet(self.filterset_base):
class Meta(MetaBase):
model = queryset.model
fields = filterset_fields
return AutoFilterSet
return None
def get_filterset_kwargs(self, request, queryset, view):
return {
"data": request.query_params,
"queryset": queryset,
"request": request,
}
def filter_queryset(self, request, queryset, view):
filterset = self.get_filterset(request, queryset, view)
if filterset is None:
return queryset
if not filterset.is_valid() and self.raise_exception:
raise utils.translate_validation(filterset.errors)
return filterset.qs
def to_html(self, request, queryset, view):
filterset = self.get_filterset(request, queryset, view)
if filterset is None:
return None
template = loader.get_template(self.template)
context = {"filter": filterset}
return template.render(context, request)
def get_coreschema_field(self, field):
if isinstance(field, filters.NumberFilter):
field_cls = compat.coreschema.Number
else:
field_cls = compat.coreschema.String
return field_cls(description=str(field.extra.get("help_text", "")))
def get_schema_fields(self, view):
# This is not compatible with widgets where the query param differs from the
# filter's attribute name. Notably, this includes `MultiWidget`, where query
# params will be of the format `<name>_0`, `<name>_1`, etc...
from django_filters import RemovedInDjangoFilter25Warning
warnings.warn(
"Built-in schema generation is deprecated. Use drf-spectacular.",
category=RemovedInDjangoFilter25Warning,
)
assert (
compat.coreapi is not None
), "coreapi must be installed to use `get_schema_fields()`"
assert (
compat.coreschema is not None
), "coreschema must be installed to use `get_schema_fields()`"
try:
queryset = view.get_queryset()
except Exception:
queryset = None
warnings.warn(
"{} is not compatible with schema generation".format(view.__class__)
)
filterset_class = self.get_filterset_class(view, queryset)
return (
[]
if not filterset_class
else [
compat.coreapi.Field(
name=field_name,
required=field.extra["required"],
location="query",
schema=self.get_coreschema_field(field),
)
for field_name, field in filterset_class.base_filters.items()
]
)
def get_schema_operation_parameters(self, view):
from django_filters import RemovedInDjangoFilter25Warning
warnings.warn(
"Built-in schema generation is deprecated. Use drf-spectacular.",
category=RemovedInDjangoFilter25Warning,
)
try:
queryset = view.get_queryset()
except Exception:
queryset = None
warnings.warn(
"{} is not compatible with schema generation".format(view.__class__)
)
filterset_class = self.get_filterset_class(view, queryset)
if not filterset_class:
return []
parameters = []
for field_name, field in filterset_class.base_filters.items():
parameter = {
"name": field_name,
"required": field.extra["required"],
"in": "query",
"description": field.label if field.label is not None else field_name,
"schema": {
"type": "string",
},
}
if field.extra and "choices" in field.extra:
parameter["schema"]["enum"] = [c[0] for c in field.extra["choices"]]
parameters.append(parameter)
return parameters