DRF封装了很多关于请求信息的参数,我们可以通过 request获取,响应 Response 也有着规定的模板,让接口响应更加规范。
在视图中,封装了非常多的视图类,便于简化视图层操作。
APIView是DRF中提供的所有视图类的积累,它继承于django.views.View,传入的请求是DRF的 Request实例,任何APIException异常都会被捕获,并且传递给合适的响应 ,业务代码需要自己写
ViewSet,继承自APIView,没有继承拓展类,业务逻辑还得自己去写,提供action参数,进行视图和路由 的绑定,不再使用http请求作为视图方法 get post put delete 可以自己指定路由和方法绑定,实现把关于一个模型的操作都写在一个类里
GenericViewSet,继承自GenericAPIView,没有继承拓展类,业务逻辑还得自己去写,把部分公共代码实现了服用。不再使用http请求作为视图方法 get post put delete 可以自己指定路由和方法绑定,实现把关于一个模型的操作都写在一个类里
两个拓展视图集:
ModelViewSet(增删改查都可以实现了),继承了GenericAPIView,继承了五个拓展类
ReadOnlyModelViewSet(实现了获取多个数据对象和获取单一数据对象),继承了GenericAPIView、ListModelMixin 和 RetrieveModelMixin。
路由…
请求响应
Request
新建一个req应用,用于专门编写本次实验的例子,视图层代码如下;
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| def get(self,request): ''' request:<rest\_framework.request.Request: GET '/req/s1'> 用的drf request.\_request:<WSGIRequest: GET '/req/s1'> :param request: :return: ''' print(f'request:{request}') print(f'request.\_request:{request.\_request}') print('drf提供的request常用操作-------------------------------------') print(f'用户:{request.user}') print(f'地址栏参数:{request.query\_params}') print(f'地址栏参数转字典:{request.query\_params.dict()}') return Response({'msg':'ok'})
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| def post(self,request): ''' 请求体:<QueryDict: {'name': ['小王'], 'files': [<InMemoryUploadedFile: 1\_Request.txt (text/plain)>, <InMemoryUploadedFile: 1\_Response.txt (text/plain)>]}> 请求体转字典:{'name': '小王', 'files': <InMemoryUploadedFile: 1\_Response.txt (text/plain)>} {<InMemoryUploadedFile: 1\_Response.txt (text/plain)>} 请求体中的文件列表:<MultiValueDict: {'files': [<InMemoryUploadedFile: 1\_Request.txt (text/plain)>, <InMemoryUploadedFile: 1\_Response.txt (text/plain)>]}> {'ALLUSERSPROFILE': 'C:\\ProgramData', 'APPDATA': 'C:\\Users\\Luffy\\AppData\\Roaming', 省略} NSFOCUS ''' print(f'请求体:{request.data}') print(f'请求体转字典:{request.data.dict()}') print({request.data.dict().get('files')}) print(f'请求体中的文件列表:{request.FILES}')
print(request.\_request.META)
print(request.\_request.META.get('HTTP\_COMPANY')) return Response({'msg': 'ok'})
|
请求中很多键值对的数据类型并不是用的Python的字典,所以需要获取值的时候要转为字典再获取
Response
Response(data, status=None, template_name=None, headers=None, content_type=None)
返回的模板如上,举个例子
1
| return Response(data=serializer.data,status=status.HTTP\_201\_CREATED,headers={'company':'NSFOCUS'},content\_type='application/json')
|
这个每个固定的,知道里面需要传的参数即可
视图
在开篇也已经说到了各个视图类的基本内容,直接上代码:
APIView
url.py
1 2
| path('stu3/<int:pk>/',TeacherInfoAPIView.as\_view()), path('stu3/',TeacherListAPIView.as\_view()),
|
views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| class TeacherListAPIView(APIView): '''APIView不支持自定义方法,只支持get post put delete的https请求''' def get(self,request): ''' 获取list :param request: :return: ''' teacher = Teacher.objects.all() serializer = TeacherModelSerializer(instance=teacher, many=True) return Response(data=serializer.data, status=status.HTTP\_200\_OK) def post(self,request): ''' 新增数据 :param request: :return: ''' serializer = TeacherModelSerializer(data=request.data.dict()) serializer.is\_valid(raise\_exception=True) serializer.save() return Response(data=serializer.data, status=status.HTTP\_201\_CREATED) class TeacherInfoAPIView(APIView): def get(self,request,pk): '''根据id查询老师信息''' teacher = Teacher.objects.get(pk=pk) serializer = TeacherModelSerializer(instance=teacher) return Response(data=serializer.data, status=status.HTTP\_200\_OK) def put(self,request,pk): '''根据id更新''' data = request.data.dict() teacher = Teacher.objects.get(pk=pk) serializer = TeacherModelSerializer(instance=teacher,data=data) serializer.is\_valid(raise\_exception=True) serializer.save() return Response(data=serializer.data, status=status.HTTP\_200\_OK) def delete(self,request,pk): '''根据id删除,这里直接删了,因为数据库中没有isDeleted字段''' data = request.data.dict() teacher = Teacher.objects.get(pk=pk) teacher.delete() return Response(status=status.HTTP\_200\_OK)
|
ViewSet
url.py
1 2 3 4 5
| path('stu4',TeacherViewSet.as\_view(actions={'get':'list', 'post':'add', })), path('stu4/<int:pk>/', TeacherViewSet.as\_view(actions={'get': 'get\_teacherById', })),
|
view.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class TeacherViewSet(ViewSet): ''' 没有继承拓展类,业务逻辑还得自己去写,提供action参数,进行视图和路由 的绑定, 不再使用http请求作为视图方法 get post put delete 可以自己指定路由和方法绑定, 实现把关于一个模型的操作都写在一个类里 ''' def list(self,request): teacher = Teacher.objects.all() serializer = TeacherModelSerializer(instance=teacher, many=True) return Response(data=serializer.data, status=status.HTTP\_200\_OK) def add(self,request): serializer = TeacherModelSerializer(data=request.data.dict()) serializer.is\_valid(raise\_exception=True) serializer.save() return Response(data=serializer.data, status=status.HTTP\_201\_CREATED) def get\_teacherById(self,request,pk): '''根据id查询老师信息''' teacher = Teacher.objects.get(pk=pk) serializer = TeacherModelSerializer(instance=teacher) return Response(data=serializer.data, status=status.HTTP\_200\_OK)
|
写了几个,就是可以自定义函数方法了
GenericViewSet
可以把我们经常写的模型和序列化器代码抽取出来
url.py
1 2 3 4 5
| path('stu5', TeacherGenericViewSet.as\_view(actions={'get': 'list', 'post': 'create', })), path('stu5/<int:pk>/', TeacherGenericViewSet.as\_view(actions={'get': 'get\_one', })),
|
view.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class TeacherGenericViewSet(GenericViewSet): queryset = Teacher.objects.all() serializer\_class = TeacherModelSerializer def list(self, request): serializer = self.get\_serializer(instance=self.get\_queryset(), many=True) return Response(serializer.data) def create(self, request): serializer = self.get\_serializer(data=request.data) serializer.is\_valid(raise\_exception=True) serializer.save() return Response(serializer.data, status=status.HTTP\_201\_CREATED) def get\_one(self, request, pk): try: instance = self.get\_object()
serializer = self.get\_serializer(instance=instance) return Response(data=serializer.data, status=status.HTTP\_200\_OK) except Student.DoesNotExist: return Response({'msg': '老师不存在'}, status=status.HTTP\_404\_NOT\_FOUND)
|
ModelViewSet
实现了五个拓展类,所以写两行代码即可有5个http接口
url.py
1 2 3 4 5 6
| from rest\_framework.routers import DefaultRouter,SimpleRouter router = DefaultRouter()
router.register(prefix='s9',viewset=StudentMixinViewSet,basename='s9')
urlpatterns += router.urls
|
view.py
1 2 3
| class StudentModelViewSet(ModelViewSet): queryset = Student.objects.all() serializer\_class = StudentModelSerializer
|
ReadOnlyModelViewSet
只能读
url.py
1 2 3 4 5 6 7
| from rest\_framework.routers import DefaultRouter,SimpleRouter router = DefaultRouter()
router.register(prefix='stu6',viewset=StudentModelViewSet,basename='stu6') router.register(prefix='stu7',viewset=StudentReadOnlyModelViewSet,basename='stu7')
urlpatterns += router.urls
|
view.py
1 2 3 4 5 6 7 8 9 10
| ''' ViewSet GenericViewSet ModelViewSet = GenericViewSet + ListModelMixin + CreateModelMixin + UpdateModelMixin+ RetrieveModelMixin + DestoryModelMixin ReadOnlyModelViewSet = GenericViewSet + ListModelMixin + RetrieveModelMixin ''' class StudentReadOnlyModelViewSet(ReadOnlyModelViewSet): queryset = Student.objects.all() serializer\_class = StudentModelSerializer
|
路由
REST框架添加了对自动URL路由到Django的支持,并为你提供了一种简单、快速和一致的方式来将视图逻辑连接到一组URL。
在上面编写视图用例的已经写到了两种路由,第一种和Django类似,但是通过 as_view(),自适应路由(我这样理解的,不清楚对不对),就是可以根据试图层的http接口自己生成路由,在 APIView中不需要写参数。但在GenericViewSet中或者继承了GenericViewSet的视图模板中,不仅仅有http借口,此时就可以添加参数action来进行视图和路由的匹配。
对于ModelViewSet和ReadOnlyModelViewSet可以使用DefaultRouter和SimpleRouter,DefaultRouter和SimpleRouter两者简单的区别就是前者提供API页面,SimpleRouter后者只是简单的数据返回。
关于DRF路由的写法,还有自定义路由等等,可以参考中文官方文档
Django REST framework 中文文档