Django Swagger Integration

2019-07-12 08:47发布

问题:

I saw swagger documentation of Flask and Django. In Flask I can design and document my API hand-written.(Include which fields are required, optional etc. under parameters sections).

Here's how we do in Flask

class Todo(Resource):
    "Describing elephants"
    @swagger.operation(
        notes='some really good notes',
        responseClass=ModelClass.__name__,
        nickname='upload',
        parameters=[
            {
              "name": "body",
              "description": "blueprint object that needs to be added. YAML.",
              "required": True,
              "allowMultiple": False,
              "dataType": ModelClass2.__name__,
              "paramType": "body"
            }
          ],
        responseMessages=[
            {
              "code": 201,
              "message": "Created. The URL of the created blueprint should be in the Location header"
            },
            {
              "code": 405,
              "message": "Invalid input"
            }
          ]
        )

I can chose which parameters to include, and which not. But how do I implement the same in Django? Django-Swagger Document in not good at all. My main issue is how do I write my raw-json in Django.

In Django it automates it which does not allows me to customize my json. How do I implement the same kind of thing on Django?

Here is models.py file

class Controller(models.Model):
    id = models.IntegerField(primary_key = True)
    name = models.CharField(max_length = 255, unique = True)
    ip = models.CharField(max_length = 255, unique = True)
    installation_id = models.ForeignKey('Installation')

serializers.py

class ActionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Controller
        fields = ('installation',)

urls.py

from django.conf.urls import patterns, url
from rest_framework.urlpatterns import format_suffix_patterns
from modules.actions import views as views

urlpatterns = patterns('',
    url(r'(?P<installation>[0-9]+)', views.ApiActions.as_view()),
)

views.py

class ApiActions(APIView):

    """
    Returns controllers List
    """

    model = Controller
    serializer_class = ActionSerializer 

    def get(self, request, installation,format=None):

        controllers = Controller.objects.get(installation_id = installation)
        serializer = ActionSerializer(controllers)
        return Response(serializer.data)

My questions are

1) If I need to add a field say xyz, which is not in my models how do I add it?

2) Quiet similar to 1st, If i need to add a field which accepts values b/w 3 provided values,ie a dropdown. how do I add it?

3) How I add an optional field? (since in case of PUT request, I might only update 1 field and rest leave it blank, which means optional field).

4) Also how do I add a field that accepts the json string, as this api does?

Thanks

I can do all of these things in Flask by hardcoding my api. But in Django, it automates from my models, which does not(as I believe) gives me the access to customize my api. In Flask, I just need to write my API with hands and then integrate with the Swagger. Does this same thing exist in Django?

Like I just need to add the following json in my Flask code and it will answer all my questions.

# Swagger json:
    "models": {
        "TodoItemWithArgs": {
            "description": "A description...",
            "id": "TodoItem",
            "properties": {
                "arg1": { # I can add any number of arguments I want as per my requirements.
                    "type": "string"
                },
                "arg2": {
                    "type": "string"
                },
                "arg3": {
                    "default": "123",
                    "type": "string"
                }
            },
            "required": [
                "arg1",
                "arg2" # arg3 is not mentioned and hence 'opional'
            ]
        },

回答1:

Django-rest-framework does have a lot of useful utility classes such as serializers.ModelSerializer which you are using. However these are optional. You can create totally custom API endpoints.

I suggest that you follow the django rest tutorial here. Part one starts with a custom view like this

from django.forms import widgets
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES


class SnippetSerializer(serializers.Serializer):
    pk = serializers.Field()  # Note: `Field` is an untyped read-only field.
    title = serializers.CharField(required=False,
                                  max_length=100)
    code = serializers.CharField(widget=widgets.Textarea,
                                 max_length=100000)
    linenos = serializers.BooleanField(required=False)
    language = serializers.ChoiceField(choices=LANGUAGE_CHOICES,
                                       default='python')
    style = serializers.ChoiceField(choices=STYLE_CHOICES,
                                    default='friendly')

    def restore_object(self, attrs, instance=None):
        """
        Create or update a new snippet instance, given a dictionary
        of deserialized field values.

        Note that if we don't define this method, then deserializing
        data will simply return a dictionary of items.
        """
        if instance:
            # Update existing instance
            instance.title = attrs.get('title', instance.title)
            instance.code = attrs.get('code', instance.code)
            instance.linenos = attrs.get('linenos', instance.linenos)
            instance.language = attrs.get('language', instance.language)
            instance.style = attrs.get('style', instance.style)
            return instance

        # Create new instance
        return Snippet(**attrs)

Note in particular that every API field is specified manually and populated by code here. So they do not have to correspond with model fields.

Your questions

1. Custom field xyz :

As I addressed above, just create a custom serialiser and add a line

class SnippetSerializer(serializers.Serializer):
    xyz = serializers.CharField(required=False, max_length=100)
            ...

2. For options in a list, what you're looking for is a "choice" field.

See the Django documention on choice as Swagger is just the same.

3. How do I make a field optional?

Set the kwarg required=False - note that it's set above for field xyz in my example.

4. Best way to accept a JSON string

Two ways to do this.

  1. Just accept a text string and use a JSON parser in the restore_object code
  2. Define a serialiser that consumes / creates the JSON code and refer to it by name as described here