Django REST framework--类视图
- 基于类的视图
- APIView类视图
- generics通用类视图
- 视图集
- DRF框架路由
基于类的视图
项目开发中要不断思考如何让代码保持高内聚,低耦合,因此优化代码的道路上一直都不停歇。目前开发的视图是基于函数形式的,特点是灵活,缺点是功能冗余性大,面对常见的增删改查往往要写重复的代码。
REST框架可以用基于类的视图来优化代码结构
APIView类视图
用类重写视图,继承REST框架的APIView类
在sqtp
应用app目录下的views.py
文件下将request_list
和request_detail
两个视图函数修改为类视图
from django.shortcuts import render
# Create your views here.
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt # 跨站攻击防护,接口白名单处理
from rest_framework import status
from rest_framework.parsers import JSONParser # 序列化
from rest_framework.response import Response
from sqtp.models import Request # 模型
from sqtp.serializers import RequestSerializer # 自定义的序列化类
from rest_framework.decorators import api_view
from rest_framework.views import APIView # 继承APIView类视图
# 改写 request_list 视图方法
class RequestList(APIView):
'''
查询所有数据和新增单个数据的功能
'''
def get(self,request,format=None):
# 获取序列化器--针对当前数据模型的所有数据
serializer = RequestSerializer(Request.objects.all(), many=True)
return Response(serializer.data) # 使用DRF框架的响应对象,自动分配返回格式
# 处理新增请求
def post(self,request,format=None):
# 构建序列化器,反序列化,将request.data数据恢复成正常的对象实例
serializer = RequestSerializer(data=request.data)
# 校验数据是否合法
if serializer.is_valid():
serializer.save()
# 新增成功返回新增数据状态码201
return Response(serializer.data, status=status.HTTP_201_CREATED)
# 新增失败返回错误信息400,请求数据有问题
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# 改写 request_detail 视图方法
class RequestDetail(APIView):
# 覆盖父类的get_object方法实现
def get_object(self,_id):
try:
return Request.objects.get(id=_id)
except Exception:
return Response(status=status.HTTP_404_NOT_FOUND) # 返回错误状态码
def get(self,request,_id,format=None):
# 序列化,将数据对象转化为json格式
req_boj = self.get_object(_id)
# 如果是异常响应,直接返回
if isinstance(req_boj,Response):
return req_boj
serializer = RequestSerializer(req_boj)
return Response(data=serializer.data)
def put(self,request,_id,format=None):
# 采用序列化器实现修改,这里与查询不同的是,还需要把待修改的数据放到序列化器里进行覆盖
req_boj = self.get_object(_id)
# 如果是异常响应,直接返回
if isinstance(req_boj, Response):
return req_boj
serializer = RequestSerializer(req_boj, data=request.data)
# 判断data中的数据是否符合要求
if serializer.is_valid():
# 若符合要求则进行保存操作
serializer.save()
# 将修改成功的状态码返回
return Response(serializer.data, status=status.HTTP_200_OK)
# 修改失败返回错误信息400,修改传递的数据有问题
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self,request,_id,format=None):
req_boj = self.get_object(_id)
# 如果是异常响应,直接返回
if isinstance(req_boj, Response):
return req_boj
req_boj.delete() # 获取数据后进行删除
# 将删除成功的状态码返回
return Response(status=status.HTTP_204_NO_CONTENT)
修改sqtp
应用app目录下的urls.py
文件
from django.urls import path
from sqtp import views as sqtp_view
from rest_framework.urlpatterns import format_suffix_patterns
urlpatterns = [
path('requests/',sqtp_view.RequestList.as_view()), # 视图类需要调用 as_view转化
path('requests/<int:_id>',sqtp_view.RequestDetail.as_view()),
]
urlpatterns = format_suffix_patterns(urlpatterns) # 重写url
行命令python manage.py runserver 0.0.0.0:8888
启动项目,在浏览器中输入http://127.0.0.1:8888/requests/
,可以发现页面返回内容与视图函数,是一样的
generics通用类视图
使用类视图的一个好处就是可以复用相同的功能,只需传入指定的参数即可。在上面的案例中,增删改查的逻辑行为都是确定的。
REST框架为我们封装好了逻辑,可以用更少的代码来封装视图,比如采用generics模块的通用视图:通过generics.ListCreateAPIViewm
实现列出所有和新增;通过generics.RetrieveUpdateDestroyAPIView
获取单个、更新和删除功能
在sqtp
应用app目录下的views.py
文件下将request_list
和request_detail
两个视图函数修改为generics通用类视图
from rest_framework.generics import ListCreateAPIView,RetrieveUpdateDestroyAPIView # 继承generics通用类视图
# 改写 request_list 视图方法
class RequestList(ListCreateAPIView):
queryset = Request.objects.all() # 数据的查询集
serializer_class = RequestSerializer
# 改写 request_detail 视图方法
class RequestDetail(RetrieveUpdateDestroyAPIView):
queryset = Request.objects.all() # 数据的查询集
serializer_class = RequestSerializer
由于是 RequestDetail
视图类是继承RetrieveUpdateDestroyAPIView
类,所以参数id的名称要为pk
,这是底层代码GenericAPIView
类中的要求限制lookup_field = 'pk'
否则,浏览器中输入http://127.0.0.1:8888/requests/43
,就会产生报错,提示修改url配置
AssertionError: Expected view RequestDetail to be called with a URL keyword argument named "pk". Fix your URL conf, or set the `.lookup_field` attribute on the view correctly.
修改sqtp
应用app目录下的urls.py
文件,将requests/<int:_id>
修改为requests/<int:pk>
from django.urls import path
from sqtp import views as sqtp_view
from rest_framework.urlpatterns import format_suffix_patterns
urlpatterns = [
path('requests/',sqtp_view.RequestList.as_view()), # 视图类需要调用 as_view转化
path('requests/<int:pk>',sqtp_view.RequestDetail.as_view()),
]
urlpatterns = format_suffix_patterns(urlpatterns) # 重写url
重启服务,测试增删改查,依然OK!
可以发现,数据详情的编辑页面还支持按字段进行编辑,这是通用类视图提供的效果。
视图集
通过使用generics通用类视图,代码量已经减少到了不到10行,优化后的视图代码依然存在重复的部分,这部分的代码依旧可以继续优化,用ViewSet(视图集)代替View类重构视图
在sqtp
应用app目录下的views.py
文件下将RequestLis
和RequestDetail
两个视图类修改一个
from rest_framework import viewsets
class RequestViewSet(viewsets.ModelViewSet):
queryset = Request.objects.all() # 数据的查询集
serializer_class = RequestSerializer
使用REST ViewSets 的抽象后,开发人员可以集中精力对API的状态和交互进行建模,并根据常规约定自动处理URL构造。
ViewSet 类与 View 类几乎相同,不同之处在于它们提供诸如 read 或 update 之类的操作,而不是 get 或 put 等方法处理程序。
一个 ViewSet 类只绑定到一组方法处理程序,当它被实例化成一组视图的时候,通常通过使用一个 Router 类来代替自己定义复杂的URL。
DRF框架路由
因为使用的是 ViewSet 类而不是 View 类,所以连常规的URL设计都可以偷懒了。利用rest框架 的router,可以自动生成路由列表。
修改sqtp
应用app目录下的urls.py
文件
from django.urls import path,include
from sqtp import views as sqtp_view
# 使用rest框架自带的路由器生成路由列表
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'requests',sqtp_view.RequestViewSet)
urlpatterns = [
path('',include(router.urls))
]
router的作用是根据注册的路由前缀,帮助你自动生成诸如此类的路由列表,根据正则匹配参数、后缀等内容
^requests/$ [name='request-list']
^requests\.(?P<format>[a-z0-9]+)/?$ [name='request-list']
^requests/(?P<pk>[^/.]+)/$ [name='request-detail']
^requests/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='request-detail']
重启服务,测试增删改查,依然OK!