25
Okay, for those who stumble upon this question, I have figured it out. It is rather silly, and I feel a little stupid for not knowing, but in my defense, it was not clearly documented. The information was not found in DRF documentation, or inside Django REST Swagger repository. Instead it was found under django-rest-framework-docs, which is what Django REST Swagger is built off of.
To specify your query parameter to show up in your SwaggerUI as a form field, you simply comment like so:
def list(self):
"""
param1 -- A first parameter
param2 -- A second parameter
"""
...
And swagger will parse your comments and will put a form input for param1 and param2. What follows --
are the descriptions for the parameters.
38
New swagger
from rest_framework.filters import BaseFilterBackend
import coreapi
class SimpleFilterBackend(BaseFilterBackend):
def get_schema_fields(self, view):
return [coreapi.Field(
name='query',
location='query',
required=False,
type='string'
)]
class MyViewSet(viewsets.ViewSet):
filter_backends = (SimpleFilterBackend,)
def list(self, request, *args, **kwargs):
# print(request.GET.get('query')) # Use the query param in your view
return Response({'hello': 'world'}, status.HTTP_200_OK)
- [Django]-Forbidden (403) CSRF verification failed. Request aborted. Reason given for failure: Origin checking failed does not match any trusted origins
- [Django]-Django β how to specify a database for a model?
- [Django]-ImportError: Could not import settings
13
I found the rest framework swagger docs.
so we can write the parameter type(interger, char), response, etc.
the tripple ---
is necessary.
@api_view(["POST"])
def foo_view(request):
"""
Your docs
---
# YAML (must be separated by `---`)
type:
name:
required: true
type: string
url:
required: false
type: url
created_at:
required: true
type: string
format: date-time
serializer: .serializers.FooSerializer
omit_serializer: false
parameters_strategy: merge
omit_parameters:
- path
parameters:
- name: name
description: Foobar long description goes here
required: true
type: string
paramType: form
- name: other_foo
paramType: query
- name: other_bar
paramType: query
- name: avatar
type: file
responseMessages:
- code: 401
message: Not authenticated
"""
How about the situation we use the mixins class such as ModelViewSets
.
Do we need to define the list
function just to add the docs?
β No
We can do like this:
class ArticleViewSet(viewsets.ModelViewSet):
"""
Articles.
---
list: #<--- here!!
parameters:
- name: name
description: article title
get_price:
omit_serializer: true
"""
@list_route(methods=['get'])
def get_price(self, request):
pass
- [Django]-QuerySet, Object has no attribute id β Django
- [Django]-How to implement breadcrumbs in a Django template?
- [Django]-Django 1.7 throws django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet
2
Working with openapi (and not coreapi), the βsimplestβ way I found is from this core dev comment:
from rest_framework.schemas.openapi import AutoSchema
class CustomSchema(AutoSchema):
def get_operation(self, path, method):
op = super().get_operation(path, method)
op['parameters'].append({
"name": "foo",
"in": "query",
"required": True,
"description": "What foo does...",
'schema': {'type': 'string'}
})
return op
class MyViewSet(ModelViewSet):
schema = CustomSchema()
def get_queryset(self):
foo = self.request.query_params.get("foo")
if foo:
self.queryset = self.queryset.filter(foo=foo)
return self.queryset
- [Django]-What's the difference between `from django.conf import settings` and `import settings` in a Django project
- [Django]-Using SQLite in Django in production?
- [Django]-Aggregate() vs annotate() in Django
2
You can simply use @swagger_auto_schema()
to indicate any additional query parameters. Define the parameters through either:
Example:
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
class SomeViewSet(GenericViewSet):
@swagger_auto_schema(
query_serializer=MyQueryParamSerializer,
manual_parameters=[
openapi.Parameter(
'my_new_query_param',
openapi.IN_QUERY,
description="The new query param",
type=openapi.TYPE_STRING,
),
openapi.Parameter(
'my_other_query_param',
openapi.IN_QUERY,
description="Another query param",
type=openapi.TYPE_BOOLEAN,
)
],
)
def list(self, request: Request, *args, **kwargs) -> Response:
...
...
class MyQueryParamSerializer(serializers.Serializer):
my_name = serializers.CharField()
my_number = serializers.IntegerField(help_text="Some custom description for the number")
my_bool = serializers.BooleanField()
Screenshot of swagger with the custom added query parameters along with the others:
Triggered request contains the query params in the URL:
curl -X 'GET' \
'http://127.0.0.1:8000/the_path/?page=3&size=2&my_name=Taguro&my_number=100&my_bool=false&my_new_query_param=120%20percent!!!&my_other_query_param=true' \
-H 'accept: application/json'
Sample usages from documentation:
@swagger_auto_schema(method='get', manual_parameters=[test_param], responses={200: user_response})
@api_view(['GET', 'PUT', 'POST'])
def user_detail(request, pk):
...
class UserList(APIView):
@swagger_auto_schema(responses={200: UserSerializer(many=True)})
def get(self, request):
...
- [Django]-Django β update model with FormView and ModelForm
- [Django]-Anyone using Django in the "Enterprise"
- [Django]-Models.py getting huge, what is the best way to break it up?
1
Disclaimer: I am using django_filters
, so results may vary. django_filters
uses the param filter_fields
in the DRF ViewSet, which may be different than not using django_filters
.
I took inspiration from this thread and overrode the get_schema_fields()
method in the filtering backend in the following way.
settings.py
REST_FRAMEWORK = {
...
'DEFAULT_FILTER_BACKENDS': ('location.of.custom_backend.CustomDjangoFilterBackend')
...
}
custom_backend.py
import coreapi
import coreschema
from django_filters.rest_framework import DjangoFilterBackend
class CustomDjangoFilterBackend(DjangoFilterBackend):
"""
Overrides get_schema_fields() to show filter_fields in Swagger.
"""
def get_schema_fields(self, view):
assert (
coreapi is not None
), "coreapi must be installed to use `get_schema_fields()`"
assert (
coreschema is not None
), "coreschema must be installed to use `get_schema_fields()`"
# append filter fields to existing fields
fields = super().get_schema_fields(view)
if hasattr(view, "filter_fields"):
fields += view.filter_fields
return [
coreapi.Field(
name=field,
location='query',
required=False,
type='string',
) for field in fields
]
- [Django]-How to format dateTime in django template?
- [Django]-Reverse for '*' with arguments '()' and keyword arguments '{}' not found
- [Django]-Django: how to get format date in views?
1
If the query parameters are used in a filter backend, adding a get_schema_operation_parameters
method is the simplest solution:
class SimpleFilterBackend(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
foo = request.query_params.get("foo")
if foo:
queryset = queryset.filter(foo=foo)
return queryset
def get_schema_operation_parameters(self, view):
return [{
"name": "foo",
"in": "query",
"required": True,
"description": "What foo does...",
"schema": {"type": "string"}
}]
class MyViewSet(ModelViewSet):
filter_backends = [SimpleFilterBackend]
- [Django]-Django form: what is the best way to modify posted data before validating?
- [Django]-How to debug Jinja2 template?
- [Django]-Django Admin: Using a custom widget for only one model field
1
For anyone stumbling upon this later, I pieced together a few solutions and came up with this:
This is using the new openapi
instead of coreapi
.
I subclassed AutoSchema
to accept a dictionary keyed on action name and mapping to the OpenApi Operation Parameter object spec. These params get appended to the operation.
from rest_framework.schemas.openapi import AutoSchema
class ParameterSchema(AutoSchema):
def __init__(self, **kwargs):
self.parameters = kwargs.pop("parameters")
super().__init__(**kwargs)
def get_operation(self, path, method):
op = super().get_operation(path, method)
method_name = getattr(self.view, "action", method.lower())
action_parameters = self.parameters.get(method_name, [])
for param in action_parameters:
op["parameters"].append(param)
return op
class MyViewSet(viewsets.ModelViewSet):
schema = ParameterSchema(
parameters={
"list": [
{
"name": "my-param",
"in": "query",
"required": False,
"description": "Description on the param",
"schema": {"type": "boolean", "default": False},
}
]
}
)
- [Django]-Temporarily Disabling Django Caching
- [Django]-Using {% url ??? %} in django templates
- [Django]-How to add Indian Standard Time (IST) in Django?
0
Elaborating on the answers above from @vadimchin β here is a working example.
# requirements.txt
djangorestframework==3.9.3
django-rest-swagger==2.2.0
django==2.2.1
coreapi==2.3.3
I am using Viewsets in my application. I had to implement filter_queryset(self, request, queryset, view)
as suggested by @jarussi.
# models.py
from django.db import models
class Recording(models.Model):
_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=511)
# serializers.py
from models import Recording
from rest_framework import serializers
class RecordingSerializer(serializers.ModelSerializer):
class Meta:
model = Recording
fields = '__all__'
# views.py
from rest_framework import viewsets
from filters import NameFilterBackend
from serializers import RecordingSerializer
class RecordingViewSet(viewsets.ModelViewSet):
serializer_class = RecordingSerializer
queryset = Recording.objects.all()
filter_backends = (NameFilterBackend,)
# filters.py
from rest_framework.filters import BaseFilterBackend
import coreapi
class NameFilterBackend(BaseFilterBackend):
def get_schema_fields(self, view):
return [coreapi.Field(
name='name',
location='query',
required=False,
type='string',
description='name of recording'
)]
def filter_queryset(self, request, queryset, view):
try:
n = request.query_params['name']
queryset = queryset.filter(name=n)
except KeyError:
# no query parameters
pass
return queryset
- [Django]-Default filter in Django model
- [Django]-Redirect to named url pattern directly from urls.py in django?
- [Django]-Embedding a Plotly chart in a Django template
- [Django]-Suddenly when running tests I get "TypeError: 'NoneType' object is not iterable
- [Django]-How do I add a link from the Django admin page of one object to the admin page of a related object?
- [Django]-Get the file path for a static file in django code