一,自定义action

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

    • 指定url的名称,默认为action名称

      二,action原码

      1. def action(methods=None, detail=None, url_path=None, url_name=None, **kwargs):
      2. """
      3. Mark a ViewSet method as a routable action.
      4. `@action`-decorated functions will be endowed with a `mapping` property,
      5. a `MethodMapper` that can be used to add additional method-based behaviors
      6. on the routed action.
      7. :param methods: A list of HTTP method names this action responds to.
      8. Defaults to GET only.
      9. :param detail: Required. Determines whether this action applies to
      10. instance/detail requests or collection/list requests.
      11. :param url_path: Define the URL segment for this action. Defaults to the
      12. name of the method decorated.
      13. :param url_name: Define the internal (`reverse`) URL name for this action.
      14. Defaults to the name of the method decorated with underscores
      15. replaced with dashes.
      16. :param kwargs: Additional properties to set on the view. This can be used
      17. to override viewset-level *_classes settings, equivalent to
      18. how the `@renderer_classes` etc. decorators work for function-
      19. based API views.
      20. """
      21. methods = ['get'] if (methods is None) else methods
      22. methods = [method.lower() for method in methods]
      23. assert detail is not None, (
      24. "@action() missing required argument: 'detail'"
      25. )
      26. # name and suffix are mutually exclusive
      27. if 'name' in kwargs and 'suffix' in kwargs:
      28. raise TypeError("`name` and `suffix` are mutually exclusive arguments.")
      29. def decorator(func):
      30. func.mapping = MethodMapper(func, methods)
      31. func.detail = detail
      32. func.url_path = url_path if url_path else func.__name__
      33. func.url_name = url_name if url_name else func.__name__.replace('_', '-')
      34. # These kwargs will end up being passed to `ViewSet.as_view()` within
      35. # the router, which eventually delegates to Django's CBV `View`,
      36. # which assigns them as instance attributes for each request.
      37. func.kwargs = kwargs
      38. # Set descriptive arguments for viewsets
      39. if 'name' not in kwargs and 'suffix' not in kwargs:
      40. func.kwargs['name'] = pretty_name(func.__name__)
      41. func.kwargs['description'] = func.__doc__ or None
      42. return func
      43. return decorator

      三,使用方法

      1,引入action

      1. from rest_framework.decorators import action

      2,定义一个序列化器类

      ```python from rest_framework import serializers from .models import Projects

class ProjectsNamesModelSerializer(serializers.ModelSerializer):

  1. class Meta:
  2. model = Projects
  3. fields = ('id', 'name')
<a name="lApK8"></a>
## 3,自定义action方法
使用装饰器 @action(),传入methods和details等参数
```python
@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'
    }))
]

验证结果
DRF-Action - 图1

四,从表关联

需求:指定获取某个项目下对应的从表的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

验证结果
DRF-Action - 图2