查看 rest_framework.generics.CreateAPIView
rest_framework.generics.ListAPIView
可以看到很多重复的代码
rest_framework.generics.ListCreateAPIView
class ListCreateAPIView(mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView): """ Concrete view for listing a queryset or creating a model instance. """ def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs)
所以直接继承
from projects.models import Projectsfrom projects.serializer import ProjectModelSerializerfrom django_filters.rest_framework import DjangoFilterBackendfrom rest_framework import genericsclass ProjectsList(generics.ListCreateAPIView): ordering_fields = ['name', 'leader'] queryset = Projects.objects.all() serializer_class = ProjectModelSerializer filter_backends = [DjangoFilterBackend] filterset_fields = ['name', 'leader', 'tester']class ProjectDetail(generics.RetrieveUpdateDestroyAPIView): queryset = Projects.objects.all() serializer_class = ProjectModelSerializer
优化思路:使用动作来触发,而不是请求方法
from rest_framework import viewsets
viewsets
不再支持 get/post/put/delete
等请求方法,而只支持action动作
但是 ViewSet
类中没有提供 get_object()
, get_serializer
等方法
继承 viewsets.GenericViewSet
将两个类合成一个类
修改url
from django.urls import pathfrom projects import viewsurlpatterns = [ path('project/', views.ProjectsViewSet.as_view({ 'get': 'list', 'post': 'create' }), name='projects_list'), path('project/<int:pk>/', views.ProjectsViewSet.as_view({ 'get': 'retrieve', 'put': 'update', 'delete': 'destroy' }), name='project_detail')]
from projects.models import Projectsfrom rest_framework import viewsetsfrom projects.serializer import ProjectModelSerializerfrom django_filters.rest_framework import DjangoFilterBackendclass ProjectsViewSet(viewsets.ModelViewSet): ordering_fields = ['name', 'leader'] queryset = Projects.objects.all() serializer_class = ProjectModelSerializer filter_backends = [DjangoFilterBackend] filterset_fields = ['name', 'leader', 'tester']
Django中
DRF中
视图集
action和请求方法的映射
from rest_framework import routers
第一个参数prefix为路由前缀,一般添加为应用名称即可 第二个参数viewset为视图集「不要加as_view」
from django.urls import path, includefrom projects import viewsfrom rest_framework import routers# 1.创建SimpleRouter路由对象router = routers.SimpleRouter()# 2.注册路由# 第一个参数prefix为路由前缀,一般添加为应用名称即可# 第二个参数viewset为视图集「不要加as_view」router.register(r'projects',views.ProjectsViewSet)urlpatterns = [ # 将自动生成的路由添加到列表中 path('',include(router.urls))]
from rest_framework.decorators import action
def action(methods=None, detail=None, url_path=None, url_name=None, **kwargs): """ Mark a ViewSet method as a routable action. Set the `detail` boolean to determine if this action should apply to instance/detail requests or collection/list requests. """ 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('_', '-') 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
可以使用action装饰器来声明自定义的动作
默认情况下,实例方法名就是动作名
methods
参数用于指定该动作支持的请求方法,默认为get
detail
用于指定该动作要处理的是否为详情资源对象「url是否需要传递pk值」
在 url.py
中添加
path('project/names/', views.ProjectsViewSet.as_view({ 'get', 'names'}))
新增序列化器
class ProjectNameSerializer(serializers.ModelSerializer): class Meta: model = Projects fields = ('id', 'name')
在 view
中添加
@action(methods=['get'], detail=False)def names(self, request, *args, **kwargs): queryset = self.get_queryset() serializer = ProjectNameSerializer(instance=queryset, many=True) return Response(serializer.data)
同理添加Interface
需要通过 projects/1/interfaces/
来拿到 id=1
的 interfaces
信息
添加序列化器
class InterfacesNameSerializer(serializers.ModelSerializer): class Meta: model = Interfaces fields = ('id', 'name', 'tester')class InterfacesByProjectIdSerializer(serializers.ModelSerializer): interfaces_set = InterfacesNameSerializer(read_only=True, many=True) class Meta: model = Projects fields = ('id', 'interfaces_sets')
添加自定义action
@action(detail=True)def interfaces(self, reques, *args, **kwargs): instance = self.get_queryset() serializer = InterfacesByProjectIdSerializer(instance=instance) return Response(serializer.data)
添加 url_path
和 url_name
@action(methods=['get'], detail=False, url_path='nm', url_name='url_name')
urlpath url的路径名 urlname url的别名「应用名称-url_name」
$ http :8000/projects/names/