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 可以自己指定路由和方法绑定,实现把关于一个模型的操作都写在一个类里
两个拓展视图集:
路由…
请求响应
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 42 43 44 45
| 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 6
| 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 21 22 23
| 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 6
| 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 20 21 22 23
| 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 7
| 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 中文文档