今日内容
1 两个视图基类APIView&GenericAPIView
# Django REST framwork 提供的视图的主要作用:
控制序列化器的执行(检验、保存、转换数据)
控制数据库查询的执行
# APIView:继承了原生Django的View
# GenericAPIView:继承了APIView
-queryset = models.Book.objects.all()
-serializer_class = serializer.BookModelSerializer
-get_queryset:获取配置的queryset
-get_object:路由中的分组字段必须是pk
-get_serializer:获取配置的序列化类
# 最终总结
#两个基类
APIView:如果跟models没有关系(没有数据库相关操作),就继承它
GenericAPIView:有关数据库操作,queryset 和serializer_class
使用方法对比:
· APIView:
from rest_framework.views import APIView
# 查询多个,新增一个
class BookAPIView(APIView):
def get(self, request):
book_list = models.Book.objects.all()
ser = BookModelSerializer(instance=book_list, many=True)
return Response(ser.data)
def post(self, request):
ser = BookModelSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
# 查询/删除/修改一个
class BookDetailAPIView(APIView):
def get(self, request, id):
res = models.Book.objects.filter(pk=id).first()
ser = BookModelSerializer(instance=res)
return Response(ser.data)
def delete(self, request, id):
models.Book.objects.filter(pk=id).delete()
return Response('')
def put(self, request, id):
try:
book = models.Book.objects.get(pk=id)
ser = BookModelSerializer(instance=book, data=request.data, partial=True)
ser.is_valid(raise_exception=True)
ser.save()
return Response('成功')
except Exception as e:
return Response(str(e))
· GenericAPIView:
from rest_framework.generics import GenericAPIView
# 查询多个,新增一个
class BookGenericView(GenericAPIView):
queryset = models.Book.objects.all()
serializer_class = BookModelSerializer
def get(self, request, *args, **kwargs):
book_list = self.queryset
ser = self.get_serializer(book_list, many=True)
return Response(ser.data)
def post(self, request, *args, **kwargs):
book_list = self.queryset
ser = self.get_serializer(book_list, many=True)
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
# 查询/删除/修改一个
class BookDetailGenericView(GenericAPIView):
queryset = models.Book.objects.all()
serializer_class = BookModelSerializer
def get(self, request, *args, **kwargs):
obj = self.get_object()
ser = self.get_serializer(obj)
return Response(ser.data)
def put(self, request, *args, **kwargs):
obj = self.get_object()
ser = self.get_serializer(obj,data=request.data)
if ser.is_valid():
ser.save()
return Response('修改成功')
def delete(self, request, *args, **kwargs):
self.queryset.filter(id=kwargs.get('pk')).delete()
return Response('删除很成功')
2 五个视图扩展类
引入:由上面可以看出使用GenericAPIView封装了对模型和序列化器的操作,把图书表换成其他表时只需要重写以下两个字段:
queryset = models.Book.objects.all() # 表
serializer_class = BookModelSerializer # 序列化器
但换成其他表时还要再写这五种操作,也并不方便,所以这里引入了五个视图扩展类:
CreateModelMixin:create方法创建一条
DestroyModelMixin:destory方法删除一条
ListModelMixin:list方法获取所有
RetrieveModelMixin:retrieve获取一条
UpdateModelMixin:update修改一条
作用:提供了几种后端视图(对数据资源进行曾删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。
这五个扩展类需要搭配GenericAPIView父类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。
视图扩展类的用法:
from rest_framework.mixins import CreateModelMixin, ListModelMixin, DestroyModelMixin, RetrieveModelMixin, UpdateModelMixin
class BookGenericView(GenericAPIView,ListModelMixin,CreateModelMixin):
queryset = models.Book.objects.all()
serializer_class = BookModelSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class BookDetailGenericView(GenericAPIView, RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
queryset = models.Book.objects.all()
serializer_class = BookModelSerializer
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
3 九个视图子类
尽管五种操作已经被视图扩展类所封装,但实际上操作其他表时,还是要写5种操作的函数,这里就引入了9种视图子类,封装了5种操作,并进行了一些组合,分别是:
·CreateAPIView,
·ListAPIView,
·ListCreateAPIView,
·UpdateAPIView,
·RetrieveAPIView,
·DestroyAPIView,
·RetrieveUpdateAPIView,
·RetrieveDestroyAPIView,
·RetrieveUpdateDestroyAPIView
9个视图子类的使用方法:
from rest_framework.generics import CreateAPIView, ListAPIView, ListCreateAPIView, UpdateAPIView, RetrieveAPIView, DestroyAPIView, RetrieveUpdateAPIView, RetrieveDestroyAPIView, RetrieveUpdateDestroyAPIView
# 最后使用了两种视图子类,把之前的代码改写成以下方式
class BookGenericView(ListCreateAPIView):
queryset = models.Book.objects.all()
serializer_class = BookModelSerializer
class BookDetailGenericView(RetrieveUpdateDestroyAPIView):
queryset = models.Book.objects.all()
serializer_class = BookModelSerializer
4 视图集
'''9种子类,其实也只是等待被人打包的棋子一枚,上面的代码还是要把单个和多个对象的操作进行分离,有没有一种方法可以把一个表的操作放在一起呢?
这样就引入了视图集,首先看继承关系
'''
# ViewSetMixin:重写了as_view
# ViewSet: 继承ViewSetMixin和APIView
# GenericViewSet:继承ViewSetMixin, generics.GenericAPIView
# ModelViewSet:继承mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,mixins.ListModelMixin,GenericViewSet
# ReadOnlyModelViewSet:继承mixins.RetrieveModelMixin,mixins.ListModelMixin,GenericViewSet
4.1 ViewSet
'''
继承自APIView与ViewSetMixin,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。
ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典(如{‘get’:’list’})的映射处理工作。
在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。
'''
# views.py
class TestViewSet(ViewSet):
queryset = models.Book.objects.all()
serializer_class = BookModelSerializer
def test_action(self, request, *args, **kwargs):
return Response(self.action) # 打印出执行方法的名字
def test_post(self, request, *args, **kwargs):
return Response('测试成功!')
# url.py
path('test/', views.TestViewSet.as_view({'get': 'test_action', 'post': 'test_post'})),
4.2 GenericViewSet
'''
使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖与GenericAPIView,所以还需要继承GenericAPIView。
GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIView与ViewSetMixin,在实现了调用as_view()时传入字典(如{'get':'list'})的映射处理工作的同时,还提供了GenericAPIView提供的基础方法,可以直接搭配Mixin扩展类使用。
'''
# 举例:
# view.py
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class Student4ViewSet(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
# urls.py
urlpatterns = [
path("students7/", views.Student4ViewSet.as_view({"get": "list", "post": "create"})),
re_path("students7/(?P<pk>\d+)/", views.Student4ViewSet.as_view({"get": "retrieve","put":"update","delete":"destroy"})),
]
4.3 ModelViewSet&ReadOnlyModelViewSet
'''
·很明显,上面继承了5个视图扩展类,五种操作都要被写入ViewSet的url字典,而这五种是基本操作,必然要被封装到一起,于是有了ModelViewSet,它继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。
·ReadOnlyModelViewSet就是只读方式, 他继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin。
'''
# 在视图集中,除了上述默认的方法动作外,还可以添加自定义动作。
举例:
#view.py
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
class StudentModelViewSet(ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
def login(self,request):
"""学生登录功能"""
return Response({"message":"登录成功"})
#url.py
urlpatterns = [
path("students8/", views.StudentModelViewSet.as_view({"get": "list", "post": "create"})),
re_path("students8/(?P<pk>\d+)/",
views.StudentModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
path("stu/login/",views.StudentModelViewSet.as_view({"get":"login"}))
]
4.4 action属性
from rest_framework.viewsets import ModelViewSet
from students.models import Student
from .serializers import StudentModelSerializer
from rest_framework.response import Response
class StudentModelViewSet(ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
def get_new_5(self,request):
"""获取最近添加的5个学生信息"""
# 操作数据库
print(self.action) # 获取本次请求的视图方法名
通过路由访问到当前方法中.可以看到本次的action就是请求的方法名
5 路由的使用
# 自动生成路由
# SimpleRouter
# DefaultRouter
# 继承了ViewSetMixin的视图类,以后写路由,可以自动生成
from rest_framework import routers
# 实例化得到一个对象
router = routers.SimpleRouter()
# 注册进路由
router.register('books', views.BookSetView)
# 把自动生成的路由配置到urlpatterns中
-urlpatterns += router.urls
-re_path(r'v1/', include(router.urls))
# 配置路由的方式
-最原始的
-path('books/', views.BookAPIView.as_view()),
-ViewSetMixin的视图类
-path('books_set/', views.BookSetView.as_view({'get':'list','post':'create'}))
-ViewSetMixin的视图类
-自动生成,上面讲的
# action
-当自动生成路由的时候,由于视图类中还有其它方法,是无法自动生成路由的
-加action装饰器:
-methods:什么请求方式会触发被装饰函数的执行
-detail:是True是基于带id的路由生成的,如果是False,是基于不带id的路由生成的
-@action(methods=['get'], detail=True)
继承关系: