之前我们的视图类可以继承GenericViewSet或者ModelViewSet,
我们不用再自定义通用的action方法,但是有时候我们需要自定义action,我们该如何设计呢?
自定义action
1、手写视图逻辑
1.1、先在视图集里自定义action方法,名称为names
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') 
1.2、在路由表url.py中定义新的路由
urlpatterns = [ 
path('projects/names/',views.ProjectsViewSet.as_view({'get':'names','post':'names'})), 
] 
 支持get和post请求方式
 
 2、使用序列化器类
2.1创建一个新的序列化器类
class ProjectNameSerializer(serializers.ModelSerializer): class Meta: model = 
ProjectsModel fields = ('id', 'name') 
2.2路由表定义路由
urlpatterns = [ 
path('projects/names/',views.ProjectsViewSet.as_view({'get':'names','post':'names'})), 
] 
仅仅只有视图集继承Viewset或者GenericViewset之后,才具备方法名与action进行一一对应的功能 
2.3 重写视图类中的自定义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) 
 2.4 将ProjectNameSerializer抽离出来,并且重写get_serializer_class方法
 * 如果当前类视图中,使用了多个不同的序列化器类,那么可以将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)) ]