简体   繁体   中英

How to set data type of path parameter in drf-yasg

I use Django , the DRF , drf-yasg and Swagger Codegen to automatically build TypeScript code to access my REST API.

In the Django backend I added a path to be served with the DRF:

rest_router = routers.DefaultRouter()
rest_router.register(r'source/(?P<source_id>[0-9]+)/document', DocumentViewSet)

DocumentViewSet is a DRF ModelViewSet .

As you can see, the source_id parameter is of numeric type. However, the resulting generated API description defines the source_id parameter as type String.

Obviously the numeric regexp in the path setting is not enough so I guess I need some type annotation in the DocumentViewSet class? I tried the following code, but this showed no effect:

@swagger_auto_schema(
    manual_parameters=[
        openapi.Parameter(name="source_id",
            required=True,
            type="integer",
            in_="path",
            description="Source reference",
        ),
    ],
)
class DocumentViewSet(viewsets.ModelViewSet):
    serializer_class = rest_serializers.DocumentSerializer
    queryset = models.Document.objects.all().order_by('id')

How can I tell drf-yasg to set the source_id parameter to type Integer?

  1. The standard OpenAPISchemaGenerator on drf-yasg only checks if the path variable name matches with the view queryset model field, and uses the type of the model field if such exists. Otherwise it defaults to string. Your original code should work if the Document model has a numeric field named "source_id". Foreign relations should work as well, but it's very much possible that in that case your parameter name should be the name of the field (source) and not the id reference (source_id).

  2. @swagger_auto_schema should be applied on the view method or methods, not the view class. AFAIK applying it to view class does nothing. See https://drf-yasg.readthedocs.io/en/stable/custom_spec.html#the-swagger-auto-schema-decorator

  3. As a side quest I poked around a bit to see if it's possible to determine the type using pythons built-in typing, and the short answer is yes, but it's a bit messy. Throwing this out in case anyone finds it useful, use it with your own risk.


class CustomSchemaGenerator(OpenAPISchemaGenerator):
    def get_path_parameters(self, path, view_cls):
        parameters = super().get_path_parameters(path, view_cls)
        for p in parameters:
            if p.in_ == openapi.IN_PATH and p.type == openapi.TYPE_STRING:
                p.type = getattr(view_cls, f'path_type_{p.name}', openapi.TYPE_STRING)
        return parameters

In the above generator, we allow drf-yasg to do the initial type determination, but then add an extra step that allows overriding type in the view class.

Example view

class DocumentView(APIView):
    path_type_source_id = openapi.TYPE_INTEGER

Enable the generator with SWAGGER_SETTINGS

SWAGGER_SETTINGS = {
    'DEFAULT_GENERATOR_CLASS': 'path.to.CustomSchemaGenerator',
}

This may be something made easier in a newer version of drf_yasf, but I managed to get it working with something similar to the following way:

from django.utils.decorators import method_decorator
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework import viewsets


params = [
    openapi.Parameter("source_id",
        openapi.IN_PATH,
        description="Source reference",
        type=openapi.TYPE_INTEGER
    )
]

@method_decorator(name="list", decorator=swagger_auto_schema(manual_parameters=params))
@method_decorator(name="create", decorator=swagger_auto_schema(manual_parameters=params))
@method_decorator(name="retrieve", decorator=swagger_auto_schema(manual_parameters=params))
@method_decorator(name="update", decorator=swagger_auto_schema(manual_parameters=params))
@method_decorator(name="partial_update", decorator=swagger_auto_schema(manual_parameters=params))
@method_decorator(name="destroy", decorator=swagger_auto_schema(manual_parameters=params))
class DocumentViewSet(viewsets.ModelViewSet):
    serializer_class = rest_serializers.DocumentSerializer
    queryset = models.Document.objects.all().order_by('id')

I have here decorated all base ViewSet actions but you could decorate only the ones you need, you can also decorate your custom actions (no need to use method_decorator in that case: you can directly decorate the action with @swagger_auto_schema). Note that you could also decorate the base actions with @swagger_auto_schema directly if you were to override them in your class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM