Skip to content

Commit

Permalink
[#210] Add query param extension
Browse files Browse the repository at this point in the history
  • Loading branch information
Sonny Bakker committed Sep 29, 2022
1 parent 93fc235 commit 5c71542
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
1 change: 1 addition & 0 deletions vng_api_common/inspectors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
ReadOnlyFieldExtension,
)
from .polymorphic import PolymorphicSerializerExtension
from .query import FilterExtension
83 changes: 83 additions & 0 deletions vng_api_common/inspectors/query.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
from django.db import models
from django.utils.encoding import force_text
from django.utils.translation import gettext as _

from django_filters.filters import BaseCSVFilter, ChoiceFilter
from drf_spectacular.extensions import OpenApiFilterExtension
from rest_framework.filters import OrderingFilter

from vng_api_common.filters import URLModelChoiceFilter
from vng_api_common.inspectors.utils import get_target_field
from vng_api_common.oas import TYPE_ARRAY, TYPE_STRING
from vng_api_common.utils import underscore_to_camel


class FilterExtension(OpenApiFilterExtension):
target_class = "vng_api_common.filters.Backend"
match_subclasses = True

def get_schema_operation_parameters(self, auto_schema, *args, **kwargs):
default_parameters = self.target.get_schema_operation_parameters(
auto_schema.view
)
filterset_class = getattr(auto_schema.view, "filterset_class", None)

if isinstance(self.target, OrderingFilter) or not filterset_class:
# TODO: OrderingFilter not present in ZRC, test in other components
return default_parameters

queryset = auto_schema.view.get_queryset()

for parameter in default_parameters:
filter_field = filterset_class.base_filters[parameter["name"]]
model_field = get_target_field(queryset.model, parameter["name"])

parameter_name = underscore_to_camel(parameter["name"])

original_description = parameter.get("description")
help_text = filter_field.extra.get(
"help_text",
getattr(model_field, "help_text", "") if model_field else "",
)

if isinstance(filter_field, BaseCSVFilter):
schema = {
"type": TYPE_ARRAY,
"items": {
"type": TYPE_STRING,
},
}

if "choices" in filter_field.extra:
schema["items"]["enum"] = (
[choice[0] for choice in filter_field.extra["choices"]],
)

parameter["type"] = TYPE_ARRAY
parameter["schema"] = schema
parameter["style"] = "form"
parameter["explode"] = False
elif isinstance(filter_field, URLModelChoiceFilter):
description = _("URL to the related {resource}").format(
resource=parameter_name
)
parameter["description"] = help_text or description
parameter["format"] = "uri"
elif isinstance(filter_field, ChoiceFilter):
parameter["schema"]["enum"] = [
choice[0] for choice in filter_field.extra["choices"]
]
elif model_field and isinstance(model_field, models.URLField):
parameter["format"] = "uri"

if parameter["description"] == original_description and help_text:
parameter["description"] = force_text(help_text)

if "max_length" in filter_field.extra:
parameter["max_length"] = filter_field.extra["max_length"]
if "min_length" in filter_field.extra:
parameter["min_length"] = filter_field.extra["min_length"]

parameter["name"] = parameter_name

return default_parameters

0 comments on commit 5c71542

Please sign in to comment.