13

I am using django-rest-framwork and django-rest-swagger.

The problem is that I'm fetching data directly from the body of the request:

def put(self, request, format=None):
    """                                                                                                                                                                                                
    This text is the description for this API                                                                                                                                                          
    username -- username                                                                                                                                                                               
    password -- password                                                                                                                                                                               
    """
    username = request.DATA['username']
    password = request.DATA['password']

but when I try the request from the swagger-ui I can't specify the "parameter type" (it's by default query and can't find a way to change it from the docstring)

I have managed to get around my problem by changing some line in the function build_query_params_from_docstring from the file "introspectors.py" but I was wondering if there is another way to do it.

0

7 Answers 7

14

UPDATE: This answer only works for django-rest-swagger < 2, see the comment from @krd below.

The docs: http://django-rest-swagger.readthedocs.org/en/latest/yaml.html

If you want to put form-data:

def put(self, request, format=None):
    """
    This text is the description for this API.

    ---
    parameters:
    - name: username
      description: Foobar long description goes here
      required: true
      type: string
      paramType: form
    - name: password
      paramType: form
      required: true
      type: string
    """
    username = request.DATA['username']
    password = request.DATA['password']

For a JSON body you can do something like:

def put(...):
    """
    ...

    ---
    parameters:
    - name: body
      description: JSON object containing two strings: password and username.
      required: true
      paramType: body
      pytype: RequestSerializer
    """
    ...
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks ! I managed to find the solution since last year ;) But it can always help someone
The yaml docstring support was deprecated in after 2.0, so this will no longer work marcgibbons.github.io/django-rest-swagger/#changes-in-20
@utkbansal see answer below
2

Define a filter-class in your viewset. django-rest does not do this yaml stuff for parameters anymore. The fields you define in your filterclass will appear as fields in your openapi / swagger documentation. This is very neat.

READ full documentation.

http://www.django-rest-framework.org/apiguide/filtering/#djangofilterbackend

from django_filters.rest_framework.filterset import FilterSet

class ProductFilter(FilterSet):

    class Meta(object):
        models = models.Product
        fields = (
            'name', 'category', 'id', )


class PurchasedProductsList(generics.ListAPIView):
    """
    Return a list of all the products that the authenticated
    user has ever purchased, with optional filtering.
    """
    model = Product
    serializer_class = ProductSerializer
    filter_class = ProductFilter

    def get_queryset(self):
        user = self.request.user
        return user.purchase_set.all()

the fields defined in the filterseet will show up in de documentation. but there will be no description.

4 Comments

This is the correct answer. It's how you're supposed to implement it from Rest Swagger v2.0 and on.
How about @api_view ?
Can this answer be extended with a bit of example code?
broken link to django rest framework
2

Similar to John VanBuskirk's answer, here is what I have:

The actual manual created doc:

drf_api/business/schema.py

# encoding: utf-8
from __future__ import unicode_literals
from __future__ import absolute_import
import coreapi

schema = coreapi.Document(
    title='Business Search API',
    url='/api/v3/business/',
    content={
        'search': coreapi.Link(
            url='/',
            action='get',
            fields=[
                coreapi.Field(
                    name='what',
                    required=True,
                    location='query',
                    description='Search term'
                ),
                coreapi.Field(
                    name='where',
                    required=True,
                    location='query',
                    description='Search location'
                ),
            ],
            description='Search business listings'
        )
    }
)

Then copied the get_swagger_view function and customized it:

drf_api/swagger.py

# encoding: utf-8
from __future__ import unicode_literals
from __future__ import absolute_import
from rest_framework import exceptions
from rest_framework.permissions import AllowAny
from rest_framework.renderers import CoreJSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_swagger import renderers
from django.utils.module_loading import import_string


def get_swagger_view(schema_location):
    """
    Returns schema view which renders Swagger/OpenAPI.
    """
    class SwaggerSchemaView(APIView):
        _ignore_model_permissions = True
        exclude_from_schema = True
        permission_classes = [AllowAny]
        renderer_classes = [
            CoreJSONRenderer,
            renderers.OpenAPIRenderer,
            renderers.SwaggerUIRenderer
        ]

        def get(self, request):
            schema = None

            try:
                schema = import_string(schema_location)
            except:
                pass

            if not schema:
                raise exceptions.ValidationError(
                    'The schema generator did not return a schema Document'
                )

            return Response(schema)


    return SwaggerSchemaView.as_view()

Then hook it up to the urls.py

from ..swagger import get_swagger_view
from . import views

schema_view = get_swagger_view(schema_location='drf_api.business.schema.schema')

urlpatterns = [
    url(r'^swagger/$', schema_view),

1 Comment

If we use custom schema_view the how we'll add location='body' and how we'll show body example any idea?
0

The only way I've had success in defining parameter types is by creating a view that defines what I want without using the generator.

class SwaggerSchemaView(APIView):
permission_classes = [IsAuthenticatedOrReadOnly,]
renderer_classes = [renderers.OpenAPIRenderer, renderers.SwaggerUIRenderer]

schema = coreapi.Document(
    title='Thingy API thing',
        'range': coreapi.Link(
            url='/range/{start}/{end}',
            action='get',
            fields=[
                coreapi.Field(
                    name='start',
                    required=True,
                    location='path',
                    description='start time as an epoch',
                    type='integer'
                ),
                coreapi.Field(
                    name='end',
                    required=True,
                    location='path',
                    description='end time as an epoch',
                    type='integer'
                )
            ],
            description='show the things between the things'
        ),
    }
)

and then using that class in urls.py

urlpatterns = [
    url(r'^$', SwaggerSchemaView.as_view()),
    ...
]

Comments

0

For latest django-rest-framework > 3.7 and django-rest-swagger > 2 , go through the below link to find working solution

https://github.com/marcgibbons/django-rest-swagger/issues/549#issuecomment-371860030

Comments

0

For Django Rest Framework >= 2.0

I am using a serializer and apply to a the view function with a decorator:

from types import MethodType
from typing import Optional, List, Callable, Any

from rest_framework.decorators import api_view as drf_api_view
from rest_framework.serializers import BaseSerializer

Function = Callable[..., Any]


def api_view(
    http_method_names: Optional[List[str]] = None,
    use_serializer: Optional[BaseSerializer] = None
) -> Function:
    if use_serializer is None:
        return drf_api_view(http_method_names)

    def api_view_deco_wrap(view: Function) -> Function:
        nonlocal http_method_names, use_serializer

        decorated_view = drf_api_view(http_method_names)(view)

        if use_serializer:
            decorated_view.cls.get_serializer = \
                MethodType(lambda s: use_serializer(), decorated_view.cls)

        return decorated_view

    return api_view_deco_wrap

Then in the function I use:

@util.api_view(["POST"], use_serializer=serializers.MySerializer)
def replace(request, pk):
    pass

And works!!!

Comments

0

[enter image description here][1]For me it worked with the ManualSchema. You have to define the description and fields. See:

from rest_framework import views
import coreapi
import coreschema
from rest_framework.schemas import ManualSchema

class RegisterView(views.APIView):

    schema = ManualSchema(
        description="User register endpoint.",
        fields=[
            coreapi.Field(
                'username',
                required=True,
                location='path',
                description='A unique username',
                schema=coreschema.String(),
                ),
            coreapi.Field(
                'password',
                required=True,
                location='path',
                schema=coreschema.String(),
                ),
            ]
        )

    )
    ...


Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.