• DRF框架之自定义action


    一、自定义action

    • 使用action装饰器
    • methods
      • 支持的请求方式,为一个列表,默认为['get']
    • detail
      • 必传参数,
      • 要处理的是否是详情资源对象(即是否通过url路径获取主键)
      • True表示需要传递主键id,使用通过URL获取的主键对应的数据对象
      • False表示不需要传递主键id,不使用URL获取主键
    • url_path
      • 指定url路由名称,默认为action名称
    • url_name
      • 指定url的名称,默认为action名称

    二、action源码

    def action(methods=None, detail=None, url_path=None, url_name=None, **kwargs):
        """
        Mark a ViewSet method as a routable action.
    
        `@action`-decorated functions will be endowed with a `mapping` property,
        a `MethodMapper` that can be used to add additional method-based behaviors
        on the routed action.
    
        :param methods: A list of HTTP method names this action responds to.
                        Defaults to GET only.
        :param detail: Required. Determines whether this action applies to
                       instance/detail requests or collection/list requests.
        :param url_path: Define the URL segment for this action. Defaults to the
                         name of the method decorated.
        :param url_name: Define the internal (`reverse`) URL name for this action.
                         Defaults to the name of the method decorated with underscores
                         replaced with dashes.
        :param kwargs: Additional properties to set on the view.  This can be used
                       to override viewset-level *_classes settings, equivalent to
                       how the `@renderer_classes` etc. decorators work for function-
                       based API views.
        """
        methods = ['get'] if (methods is None) else methods
        methods = [method.lower() for method in methods]
    
        assert detail is not None, (
            "@action() missing required argument: 'detail'"
        )
    
        # name and suffix are mutually exclusive
        if 'name' in kwargs and 'suffix' in kwargs:
            raise TypeError("`name` and `suffix` are mutually exclusive arguments.")
    
        def decorator(func):
            func.mapping = MethodMapper(func, methods)
    
            func.detail = detail
            func.url_path = url_path if url_path else func.__name__
            func.url_name = url_name if url_name else func.__name__.replace('_', '-')
    
            # These kwargs will end up being passed to `ViewSet.as_view()` within
            # the router, which eventually delegates to Django's CBV `View`,
            # which assigns them as instance attributes for each request.
            func.kwargs = kwargs
    
            # Set descriptive arguments for viewsets
            if 'name' not in kwargs and 'suffix' not in kwargs:
                func.kwargs['name'] = pretty_name(func.__name__)
            func.kwargs['description'] = func.__doc__ or None
    
            return func
        return decorator

    三、使用方法

     1.引入action

    from rest_framework.decorators import action

    2.定义一个序列化器类

    from rest_framework import serializers
    from .models import Projects
    
    
    class ProjectsNamesModelSerializer(serializers.ModelSerializer):
    
        class Meta:
            model = Projects
            fields = ('id', 'name')

    3.自定义action方法

    使用装饰器@action(),传入methods和detail等参数值

    @action(methods=['get'], detail=False)
        def names(self, request):
            qs = self.filter_queryset(self.get_queryset())
            page = self.paginate_queryset(qs)
            if page:
                serializer_obj = self.get_serializer(instance=page, many=True)
                return self.get_paginated_response(serializer_obj.data)
            serializer_obj = self.get_serializer(instance=qs, many=True)
            return Response(serializer_obj.data)

    4.重写get_serializer_class方法

    使用self.action可以获取到传入的action,因此可以使用if判断来满足特定条件下返回不同的序列化器类

        def get_serializer_class(self):
            if self.action == 'names':
                return ProjectsNamesModelSerializer
            else:
                return self.serializer_class

    5.配置路由信息

    from django.contrib import admin
    from django.urls import path
    from projects.views import ProjectsPageSet
    
    
    urlpatterns = [
        path('admin/', admin.site.urls)
        path('projects/names/', ProjectsPageSet.as_view({
            'get': 'names'
        }))
    ]

    验证结果:

    四、从表关联

    需求:指定获取某个项目下对应的从表的id和name?

    1.定义序列化器类

    from rest_framework import serializers
    from .models import Projects
    from interfaces.models import Interfaces
    
    
    class InterfacesNamesModelSerializer(serializers.ModelSerializer):
    
        class Meta:
            model = Interfaces
            fields = ('id', 'name')
    
    
    class InterfacesByProjectIdModelSerializer(serializers.ModelSerializer):
        interfaces = InterfacesNamesModelSerializer(many=True, read_only=True, label='从表id', help_text='从表id')
    
        class Meta:
            model = Projects
            fields = ('id', 'interfaces')

    2.自定义action方法

    @action(methods=['get'], detail=True)
        def interfaces(self, request, *args, **kwargs):
            qs = self.get_object()
            serializer_obj = self.get_serializer(instance=qs)
            return Response(serializer_obj.data)

    3.重写get_serializer_class方法

        def get_serializer_class(self):
            if self.action == 'interfaces':
                return InterfacesByProjectIdModelSerializer
            else:
                return self.serializer_class

    验证结果:

  • 相关阅读:
    Linux 创建sftp用户并限制目录权限
    idea操作maven时控制台中文显示乱码/maven项目启动方式
    Docker 容器镜像删除
    Golang 在 Mac、Linux、Windows 下如何交叉编译
    Linux后台运行Jar方法
    MAC安装JDK及环境变量配置
    Docker 容器镜像删除
    UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)
    《设计模式之禅》之状态模式
    《设计模式之禅》之访问者模式
  • 原文地址:https://www.cnblogs.com/xiaogongjin/p/13340526.html
Copyright © 2020-2023  润新知