上一章:
七、Django DRF框架GenericAPIView--搜索&排序&分页&返回值_做测试的喵酱的博客-CSDN博客
下一章:
九、DRF生成API文档_做测试的喵酱的博客-CSDN博客
一、视图集ModelViewSet与ReadOnlyViesSet
ModelViewSet视图集 与 ReadOnlyViesSet视图集
1、ModelViewSet视图集:支持增删改查,如果需要对某个模型进行增删改查操作,才会选择ModelViewSet
2、ReadOnlyViesSet视图集:只支持读取操作,如果仅仅只对某个模型进行数据读取操作(取列表数据接口、获取详情数据接口),一般会选择ReadOnlyModelViewSet。
二、视图集ModelViewSet
ModelViewSet是一个最完整的视图集类。
1、提供了获取列表数据接口、获取详情数据接口、创建数据接口、更新数据接口、删除数据的接口(增删改查接口)
2、如果需要对某个模型进行增删改查操作,才会选择ModelViewSet
3、如果仅仅只对某个模型进行数据读取操作(取列表数据接口、获取详情数据接口),一般会选择ReadOnlyModelViewSet
class ProjectViewSet(viewsets.ModelViewSet):
"""
list:
获取项目列表数据
retrieve:
获取项目详情数据
update:
更新项目信息
names:
获取项目名称
"""
queryset = Projects.objects.all()
serializer_class = ProjectModelSerializer
filter_backends = [filters.SearchFilter, filters.OrderingFilter]
search_fields = ['=name', '=leader', '=id']
ordering_fields = ['id', 'name', 'leader']
# 可以在类视图中指定分页引擎类,优先级高于全局
pagination_class = PageNumberPagination
2.0 类视图的设计原则
a.类视图尽量要简单
b.根据需求选择相应的父类视图
c.如果DRF中的类视图有提供相应的逻辑,那么就直接使用父类提供的
d.如果DRF中的类视图,绝大多数逻辑都能满足需求,可以重写父类实现
e.如果DRF中的类视图完全不满足要求,那么就直接自定义即可
2.1 自定义视图集方法action
场景:当视图集默认提供的方法,不能满足需求时,可以自定义action方法。
@action(methods=['GET'], detail=False)
def names(self, request, *args, **kwargs):
# queryset = self.get_queryset()
# queryset = self.filter_queryset(queryset)
# names_list = []
# for project in queryset:
# names_list.append({
# 'id': project.id,
# 'name': project.name
# })
# serializer = self.get_serializer(queryset, many=True)
#
# # return Response(names_list, status=200)
# return Response(serializer.data, status=200)
return super().list(request, *args, **kwargs)
2.1.1 函数定义
2.1.2 action装饰
@action(methods=['GET'], detail=False, url_path='xxx', url_name='yyyy')
如果需要使用路由器机制自动生成路由条目,那么就必须得使用action装饰器
1、methods(非必填)指定需要使用的请求方法,如果不指定,默认为GET
2、detail(必填)指定是否为详情接口,是否需要传递当前模型的pk值
如果需要传递当前模型的pk值,那么detail=True,否则detail=False
3、url_path指定url路径,默认为action方法名称
4、url_name指定url路由条目名称后缀,默认为action方法名称
127.0.0.1:8000/projects/names/
127.0.0.1:8000/projectsxxx/$[name='projects-yyy']
@action(detail=True)
def interfaces(self, request, *args, **kwargs):
project = self.get_object()
interfaces_qs = project.interfaces_set.all()
interfaces_data = [{'id': interface.id, 'name': interface.name} for interface in interfaces_qs]
return Response(interfaces_data, status=200)
127.0.0.1:8000/projects/12/interfaces/
三、路由 routers
3.1 SimpleRouter路由
引入
from rest_framework import routers
1、可以使用路由器对象,为视图集类自动生成路由条目
2、路由器对象默认只为通用action(create、list、retrieve、update、destroy)生成路由条目,自定义的action不会生成路由条目
3、创建SimpleRouter路由对象
router = routers.SimpleRouter()
4、使用路由器对象调用register方法进行注册
router.register(r'projects', views.ProjectViewSet)
- prefix指定路由前缀,如上r‘projects’
- viewset指定视图集类,不可调用as_view,如上views.ProjectViewSet
5、设置路由条目
方式一:路由器对象.urls属性可获取生成的路由条目
urlpatterns = [
# 路由器对象.urls属性可获取生成的路由条目
path('', include(router.urls)),
]
方式二:两个路由列表相加
# router.urls为列表
urlpatterns += router.urls
3.2 DefaultRouter路由
创建SimpleRouter路由对象
router = routers.SimpleRouter()
创建DefaultRouter路由对象
router = routers.DefaultRouter()
DefaultRouter与SimpleRouter功能类似,仅有的区别为:DefaultRouter会自动生成一个根路由(显示获取数据的入口)
3.3 自定义action的路由处理
方式一:@action装饰器处理路由
自定义的action,不会自动生成路由,需要引入@action装饰器处理。
@action(methods=['GET'], detail=False)
def names(self, request, *args, **kwargs):
return super().list(request, *args, **kwargs)
@action(detail=True)
def interfaces(self, request, *args, **kwargs):
project = self.get_object()
interfaces_qs = project.interfaces_set.all()
interfaces_data = [{'id': interface.id, 'name': interface.name} for interface in interfaces_qs]
return Response(interfaces_data, status=200)
# 1、如果需要使用路由器机制自动生成路由条目,那么就必须得使用action装饰器
# 2、methods指定需要使用的请求方法,如果不指定,默认为GET
# 3、detail指定是否为详情接口,是否需要传递当前模型的pk值
# 如果需要传递当前模型的pk值,那么detail=True,否则detail=False
# 4、url_path指定url路径,默认为action方法名称
# 5、url_name指定url路由条目名称后缀,默认为action方法名称
# @action(methods=['GET'], detail=False, url_path='xxx', url_name='yyyy')
方式二:在urls.py文件中,指定路由
四、同一个视图集ModelViewSet中,对同一个模型类不同形式的输出
场景:
一个视图集ModelViewSet,下有多个action方法,比如获取list 、获取数据详情retrieve
这两个action获取的是同一个序列化器类。
当我要求获取数据列表与获取详情的内容 展示字段不同。
4.1 视图集ModelViewSet 采用多个序列化器类
场景:
一个视图集ModelViewSet,下有多个action方法,比如获取list 、获取数据详情retrieve
这两个action获取的是同一个序列化器类。
当我要求获取数据列表与获取详情的内容 展示字段不同时,需要采用多个序列化器类。
一个视图集ModelViewSet,如何使用多个action对应多个序列化器?
重写get_serializer_class 方法。
def get_serializer_class(self):
"""
a.可以重写父类的get_serializer_class方法,用于为不同的action提供不一样的序列化器类
b.在视图集对象中可以使用action属性获取当前访问的action方法名称
:return:
"""
if self.action == 'names':
return ProjectsNamesModelSerailizer
else:
# return self.serializer_class
return super().get_serializer_class()
4.2 重写action方法
场景:
一个视图集ModelViewSet,下有多个action方法,比如获取list 、获取数据详情retrieve
这两个action获取的是同一个序列化器类。
当我要求获取数据列表与获取详情的内容 展示字段不同时,重写action方法。
将多余的返回值干掉
def retrieve(self, request, *args, **kwargs):
response = super().retrieve(request, *args, **kwargs)
response.data.pop('id')
response.data.pop('create_time')
return response