之前我们的视图类可以继承GenericViewSet或者ModelViewSet,我们不用再自定义通用的action方法,但是有时候我们需要自定义action,我们该如何设计呢?
- class ProjectsViewSet(
- viewsets.ModelViewSet):
- # 指定当前类视图需要使用的查询集
- queryset = ProjectsModel.objects.all()
- # 指定当前类视图需要使用的序列化器类
- serializer_class = ProjectModelSerializer
- # lookup_field = 'Id'
- # 声明需要使用的引擎类
- filter_backends = [filters.SearchFilter,
- filters.OrderingFilter
- ]
- # 定义需要过滤的字段
- search_fields = ['name', 'id']
-
- # 定义需要排序的字段
- ordering_fields = ['id', 'name']
- # 声明需要使用的分页引擎
- pagination_class = PageNumberPagination
- @action(methods=['GET', 'POST'], detail=False)
- def names(self, request, *args, **kwargs):
- qs = self.get_queryset()
- lst = []
- for obj in qs:
- dict = {
- 'id': obj.id,
- 'name': obj.name,
- }
- lst.append(dict)
- return Response(lst, content_type='application/json')
- urlpatterns = [
- path('projects/names/',views.ProjectsViewSet.as_view({'get':'names','post':'names'})),
- ]
支持get和post请求方式
- class ProjectNameSerializer(serializers.ModelSerializer):
-
- class Meta:
- model = ProjectsModel
- fields = ('id', 'name')
- urlpatterns = [
- path('projects/names/',views.ProjectsViewSet.as_view({'get':'names','post':'names'})),
- ]
仅仅只有视图集继承Viewset或者GenericViewset之后,才具备方法名与action进行一一对应的功能
- from .serializers import ProjectNameSerializer
- @action(methods=['GET', 'POST'], detail=False)
- def names(self, request, *args, **kwargs):
- qs = self.get_queryset()
- # lst = []
- # for obj in qs:
- # dict = {
- # 'id': obj.id,
- # 'name': obj.name,
- # }
- # lst.append(dict)
- # return Response(lst, content_type='application/json')
- serializer_obj = ProjectNameSerializer(instance=qs, many=True)
- return Response(serializer_obj.data, status=status.HTTP_200_OK)
- 如果当前类视图中,使用了多个不同的序列化器类,那么可以将get_serializer_class重写
- 继承视图集类之后,会提供action属性,指定当前请求的action方法名称
- 可以根据不同的action去选择不同的序列化器类(不同的查询集)
- @action(methods=['GET', 'POST'], detail=False)
- def names(self, request, *args, **kwargs):
- qs = self.get_queryset()
- serializer_obj=self.get_serializer(instance=qs, many=True)
- return Response(serializer_obj.data, status=status.HTTP_200_OK)
-
- def get_serializer_class(self):
- if self.action=='names':
- return ProjectNameSerializer
- return self.serializer_class
如果请求的是/projects/names/,使用的是自定义的序列化器类进行数据输出
如果请求的是其他路由路径,能够使用全局指定的序列化器类(serializer_class=ProjectModelSerializer)正常处理数据,进行序列化输出
- 可以使用action装饰器,指定自定义action方法(使用路由器时,会自动生成路由条目)
- 如果不指定methods,那么当前action只支持GET方法请求
- 可以指定当前action支持多个请求方法,需要将请求方法大写添加至列表中
- detail指定当前action是否为详情视图
- url_path指定url的路径字符串
- url_name指定url路径的名称
- 如果不指定url_path和url_name,默认为action方法名称
在路由表中导入routers
- from rest_framework import routers
-
- router = routers.SimpleRouter()
- # 注册路由
- router.register(r'projects', views.ProjectsViewSet)
-
- urlpatterns = router.urls
-
注册路由:
- 仅仅只有视图集才支持定义路由器功能
- register方法可以注册路由条目
- 第一个参数为路由条目的前缀,往往需要添加r'子应用名'
- 第二个参数为视图集对象,无需调用as_view({})
- 可以定义DefaultRouter对象,相比SimpleRouter路由对象,会自动添加一个根路由(指定当前项目的入口地址)
- router = routers.DefaultRouter()
如果没有指定url_path和url_name,则通过路由名称去获取URL路径
如果在action里指定了url_path和url_name,则url_path指定url的路径字符串,url_name指定url路径的名称
- @action(methods=['GET', 'POST'], detail=False,url_path='na', url_name='an')
- def names(self, request, *args, **kwargs):
- qs = self.get_queryset()
有时候,有些路由我们不想通过路由器生成,需要在urlpatterns里生成
方式一:可以附加router.urls
到现有视图的列表.
- from rest_framework import routers
-
- router = routers.SimpleRouter()
- # 注册路由
- router.register(r'projects', views.ProjectsViewSet)
- urlpatterns = []
- urlpatterns += router.urls
方式二:或者可以使用 Django 的include
函数,就像这样
- from rest_framework import routers
-
- router = routers.SimpleRouter()
- # 注册路由
- router.register(r'projects', views.ProjectsViewSet)
- urlpatterns = [
- path('', include(router.urls))
- ]
-