Bob's Blog

Web开发、测试框架、自动化平台、APP开发、机器学习等

返回上页首页

Django restframework加Vue打造前后端分离的网站(十三)URL和Swagger中的自定义参数



在该系列的第九篇(查询筛选和搜索)中提到了筛选并返回部分符合条件的业务对象,要么放在url中http://127.0.0.1:8000/automation/api/computer/{type}/,要么是放在get请求的body中。此外,还有一种方式,类似一种筛选条件,http://127.0.0.1:8000/automation/api/computer/?type=tablet&year=2020,因为会涉及到swagger中的parameter的显示,这里就放在一起记录。

使用/?type=tablet&year=2020这种方式,不需要新加url路由,相当于传递{"type": "tablet", "year": "2020"}。如果我们需要对这两个参数做处理,就需要重写get_queryset这个方法。比如:

from .models import Computer
from .serializers import ComputerSerializer
from rest_framework import generics
from rest_framework import filters


class ComputerList(generics.ListCreateAPIView):
    """
        get:
            Return all computers.

        post:
            Create a new computer.
    """
    serializer_class = ComputerSerializer
    filter_backends = [filters.SearchFilter]
    search_fields = ["=computer_type"]

    def get_queryset(self):
        queryset = Computer.objects.all().order_by("-id")
        publish_year = self.request.query_params.get('year', None)
        computer_type = self.request.query_params.get('type', None)
        if publish_year:
            queryset = queryset.filter(publish_year=publish_year)
        if computer_type:
            queryset = queryset.filter(computer_type=computer_type)
        return queryset

此时便能接受处理year和type这两个url中的参数。并且返回符合条件的业务对象。如果url中有其他的不识别参数,这里也不会处理。

不过当我们现在打开swagger的docs页面时,却发现没有我们支持的这两个参数,只有我们用到的分页参数(page)和搜索参数(s)。如下图:

当我们点击"try it out"时,便只能尝试page和s。

对于目前支持的参数怎么办呢?要么是在doc中添加注释,类似:

    """
        get:
            Return all computers.
           --
            parameters:
              type: get computer list by computer type
              year: get computer list by publish year

        post:
            Create a new computer.
    """

swagger的显示便会变成这样,用来提示可以使用这两个参数。

不过这里只是起到了提示作用,不能在页面上直接尝试,需要在其他工具或者脚本中尝试这两个参数类别。

接下来就需要在swagger页面中添加自定义的参数,并可支持当前页面发请求。

此时在view.py中新建一个类:SimpleFilterBackend,并在ComputerList中的filter_backend指定。代码类似:

from .models import Computer
from .serializers import ComputerSerializer
from rest_framework import generics
from rest_framework import filters
from rest_framework.filters import BaseFilterBackend
from rest_framework.compat import coreapi


class SimpleFilterBackend(BaseFilterBackend):
    def get_schema_fields(self, view):
        return [coreapi.Field(
            name='type',
            location='query',
            required=False,
            type='string',
            description= 'filter by computer type'
        ), coreapi.Field(
            name='year',
            location='query',
            required=False,
            type='string',
            description= 'filter by publish year'
        )]

    def filter_queryset(self, request, queryset, view):
        return queryset


class ComputerList(generics.ListCreateAPIView):
    """
        get:
            Return all computers.
           --
            parameters:
              type: get computer list by computer type
              year: get computer list by publish year

        post:
            Create a new computer.
    """
    serializer_class = ComputerSerializer
    filter_backends = [filters.SearchFilter, SimpleFilterBackend]
    search_fields = ["=computer_type"]

    def get_queryset(self):
        queryset = Computer.objects.all().order_by("-id")
        publish_year = self.request.query_params.get('year', None)
        computer_type = self.request.query_params.get('type', None)
        if publish_year:
            queryset = queryset.filter(publish_year=publish_year)
        if computer_type:
            queryset = queryset.filter(computer_type=computer_type)
        return queryset

此时swagger的页面就变成如下,并且可以支持当前页面尝试请求操作。

但是用这种方式有个问题,就是不同的view中涉及到的url参数名都可能不一样,如果用这种方式,那么每次都需要新定义一个SimpleFilterBackend并指定,不是太方便。

于是该方式可以更新为从doc中取值,动态的生成paramter。只是该方法会导致上面图片中的黄色部分的注释消失,因为要修改注释的格式。

先在utils中新增一个文件,并使其从doc中取出参数的信息。

from rest_framework.filters import BaseFilterBackend
from rest_framework.compat import coreapi
import yaml


class ParameterFilter(BaseFilterBackend):

    def get_schema_fields(self, view):
        default = {
            "name": "no name",
            "location": "query",
            "required": False,
            "type": "string",
            "description": "no description"
        }
        params = yaml.load(view.__doc__)["parameters"]
        fields = []
        for p in params:
            new_p = {}
            for k in default.keys():
                if k in p.keys():
                    new_p[k] = p[k]
                else:
                    new_p[k] = default[k]
            fields.append(coreapi.Field(
                name=new_p["name"],
                location=new_p["location"],
                required=new_p["required"],
                type=new_p["type"],
                description=new_p["description"]
            ))
        return fields

    def filter_queryset(self, request, queryset, view):
        return queryset

然后修改view.py中的注释信息和filter_backend:

from .models import Computer
from .serializers import ComputerSerializer
from rest_framework import generics
from rest_framework import filters
from utils.parameter_filter import ParameterFilter

class ComputerList(generics.ListCreateAPIView):
    """
        get:
            Return all computers.

        parameters:
          - name: type
            description: filter by computer type
          - name: year
            description: filter by publish year

        post:
            Create a new computer.
    """
    serializer_class = ComputerSerializer
    filter_backends = [filters.SearchFilter, ParameterFilter]
    search_fields = ["=computer_type"]

    def get_queryset(self):
        queryset = Computer.objects.all().order_by("-id")
        publish_year = self.request.query_params.get('year', None)
        computer_type = self.request.query_params.get('type', None)
        if publish_year:
            queryset = queryset.filter(publish_year=publish_year)
        if computer_type:
            queryset = queryset.filter(computer_type=computer_type)
        return queryset

此时在swagger界面中就变成这个样子:

参考文章:https://github.com/marcgibbons/django-rest-swagger/issues/604

下一篇:  Mac上Parallels Desktop里安装Kali
上一篇:  Django restframework加Vue打造前后端分离的网站(十二)vue生命周期的事件

共有0条评论

添加评论

暂无评论