一,自定义action
- 使用action装饰器
- methods
- 支持的请求方式,为一个列表,默认为[‘get’]
- detail
- 必传参数
- 要处理的是否为详情资源对象(是否需要通过url路径获取主键)
- True表示需要传递主键id,使用通过URL获取的主键对应的数据对象
- False表示不需要传递主键id,不使用URL获取主键
- url_path
- 指定url路由名称,默认为action名称
url_name
-
二,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,定义一个序列化器类
```python from rest_framework import serializers from .models import Projects
-
class ProjectsNamesModelSerializer(serializers.ModelSerializer):
class Meta:
model = Projects
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'
}))
]
四,从表关联
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
验证结果