Skip to content

Commit 5c71542

Browse files
author
Sonny Bakker
committed
[#210] Add query param extension
1 parent 93fc235 commit 5c71542

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

vng_api_common/inspectors/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
ReadOnlyFieldExtension,
66
)
77
from .polymorphic import PolymorphicSerializerExtension
8+
from .query import FilterExtension

vng_api_common/inspectors/query.py

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
from django.db import models
2+
from django.utils.encoding import force_text
3+
from django.utils.translation import gettext as _
4+
5+
from django_filters.filters import BaseCSVFilter, ChoiceFilter
6+
from drf_spectacular.extensions import OpenApiFilterExtension
7+
from rest_framework.filters import OrderingFilter
8+
9+
from vng_api_common.filters import URLModelChoiceFilter
10+
from vng_api_common.inspectors.utils import get_target_field
11+
from vng_api_common.oas import TYPE_ARRAY, TYPE_STRING
12+
from vng_api_common.utils import underscore_to_camel
13+
14+
15+
class FilterExtension(OpenApiFilterExtension):
16+
target_class = "vng_api_common.filters.Backend"
17+
match_subclasses = True
18+
19+
def get_schema_operation_parameters(self, auto_schema, *args, **kwargs):
20+
default_parameters = self.target.get_schema_operation_parameters(
21+
auto_schema.view
22+
)
23+
filterset_class = getattr(auto_schema.view, "filterset_class", None)
24+
25+
if isinstance(self.target, OrderingFilter) or not filterset_class:
26+
# TODO: OrderingFilter not present in ZRC, test in other components
27+
return default_parameters
28+
29+
queryset = auto_schema.view.get_queryset()
30+
31+
for parameter in default_parameters:
32+
filter_field = filterset_class.base_filters[parameter["name"]]
33+
model_field = get_target_field(queryset.model, parameter["name"])
34+
35+
parameter_name = underscore_to_camel(parameter["name"])
36+
37+
original_description = parameter.get("description")
38+
help_text = filter_field.extra.get(
39+
"help_text",
40+
getattr(model_field, "help_text", "") if model_field else "",
41+
)
42+
43+
if isinstance(filter_field, BaseCSVFilter):
44+
schema = {
45+
"type": TYPE_ARRAY,
46+
"items": {
47+
"type": TYPE_STRING,
48+
},
49+
}
50+
51+
if "choices" in filter_field.extra:
52+
schema["items"]["enum"] = (
53+
[choice[0] for choice in filter_field.extra["choices"]],
54+
)
55+
56+
parameter["type"] = TYPE_ARRAY
57+
parameter["schema"] = schema
58+
parameter["style"] = "form"
59+
parameter["explode"] = False
60+
elif isinstance(filter_field, URLModelChoiceFilter):
61+
description = _("URL to the related {resource}").format(
62+
resource=parameter_name
63+
)
64+
parameter["description"] = help_text or description
65+
parameter["format"] = "uri"
66+
elif isinstance(filter_field, ChoiceFilter):
67+
parameter["schema"]["enum"] = [
68+
choice[0] for choice in filter_field.extra["choices"]
69+
]
70+
elif model_field and isinstance(model_field, models.URLField):
71+
parameter["format"] = "uri"
72+
73+
if parameter["description"] == original_description and help_text:
74+
parameter["description"] = force_text(help_text)
75+
76+
if "max_length" in filter_field.extra:
77+
parameter["max_length"] = filter_field.extra["max_length"]
78+
if "min_length" in filter_field.extra:
79+
parameter["min_length"] = filter_field.extra["min_length"]
80+
81+
parameter["name"] = parameter_name
82+
83+
return default_parameters

0 commit comments

Comments
 (0)