Django-drf-视图家族合集

概述

在drf中,一般使用CBV(class-base-view)去写视图层的功能,在原生的Django中,使用FBV(function-base-view)较多,不过,即使是写CBV,底层实现也是FBV

所有视图的关系总结

View:Django中字典的原生的类,后续所有的类都是来自于它,是一个基类

APIView:继承自View,在drf中,所有的视图类,都来自于它,是一个基类,和View最大的区别就是重写了as_view方法,是drf中视图的起源

  若继承APIView去写对应的接口的话,那么每一个接口都需要手动去写,获取数据、序列化等

GenericAPIView:继承自APIView,和APIView的区别就是,封装了query_set和serializer_class,写接口的时候,指定了这两个参数,那么查询数据使用对象的方法即可,不需要写ORM语句了,如self.get_object() 查询一条、self.get_query_set() 获取所有等

5个扩展类:CreateModelMixin、ListModelMixin、RetrieveModelMixin、UpdateModelMixin、DestroyModelMixin

  这5个扩展类没有继承任何类,是5个基类,使用时,可以仅继承它们,如继承ListModelMixin,不过极其不推荐使用,把接口写复杂了,因为ListModelMixin是没有as_view方法的,单单继承这个类,不如直接写一个FBV的函数,这个类的内部也只是封装了ORM的操作而已

  所以组合最好的是GenericAPIView,写接口时,指定queryset和serializer_class,然后返回扩展类对应的方法即可

9个视图子类:ListAPIView、CreateAPIView、DestroyAPIView、UpdateAPIView、RetrieveAPIView、ListCreateAPIView、RetrieveDestroyAPIView、RetrieveUpdateAPIView、RetrieveUpdateDestroyAPIView

  是5个视图扩展类结合GenericAPIView得到的类,写接口时,指定queryset和serializer_class即可,不需要再写方法了,除非这9个没有想要的功能,那就需要单独的写接口

 视图集:ViewSetMixin、ViewSet、GenericViewSet、ModelViewSet、ReadOnlyModelViewSet

  最主要的就是ViewSetMixin,重写了as_view方法,改变了路由的写法,请求方式对应对应的方法名即可

  ModelViewSet是方法最全的类,如果这里没有需要的功能,那就需要自己写方法来实现

两个视图基类:View、APIView

一般仅在原生的Django中,才会使用到View,所以这里暂不展开,仅针对APIView,且由于与数据库交互较多,所以序列化器使用ModelSerializer

模型表、配置文件、序列化器准备

模型表

class Book(models.Model):
    name = models.CharField(max_length=32, verbose_name='书名')
    price = models.DecimalField(max_digits=5, decimal_places=2)
    author = models.CharField(max_length=32, verbose_name='作者')
    publish = models.CharField(max_length=32, verbose_name='出版社信息')

 

序列化器

from rest_framework import serializers
from . import models

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = '__all__'

修改配置

 

# 注册app

# 配置数据库,导入pymysql

# 国际化配置

APIView

使用APIView写5个接口,每一个方法都需要手动地写。

from rest_framework.views import APIView
from rest_framework.response import Response

路由配置

urlpatterns = [
    path('book/', views.BookAPIView.as_view()),
    re_path('book/(?P<pk>\d+)', views.BookDetailAPIVIew.as_view()),

]

查询所有

class BookAPIView(APIView):
    # 查询所有
    def get(self, request, *args, **kwargs):
        # 1 获取数据
        book_list = models.Book.objects.all()
        # 2 序列化数据
        book_ser = serializer.BookModelSerializer(instance=book_list, many=True)
        # 3 返回序列化后的数据
        return Response(book_ser.data)

新增一条

class BookAPIView(APIView):# 增加一条
    def post(self,request,*args,**kwargs):
        # 直接序列化,不需要去数据库查询
        book_ser = serializer.BookModelSerializer(data=request.data)
        # 校验
        if book_ser.is_valid():
            # 校验通过,保存数据
            book_ser.save()
            # 根据RESTFul规范,返回创建后的数据
            return Response(book_ser.data)
        else:
            # 未通过校验
            return Response(book_ser.errors)

查询一条

class BookDetailAPIVIew(APIView):
    # 查询一条
    def get(self,request,pk,*args,**kwargs):
        # 1 查询数据
        print(pk)
        book = models.Book.objects.filter(pk=pk).first()
        # 2 序列化
        book_ser = serializer.BookModelSerializer(instance=book)
        # 3 返回数据
        return Response(book_ser.data)

修改一条

class BookDetailAPIVIew(APIView):
# 修改一条
    def put(self,request,pk,*args,**kwargs):
        # 1 查询数据
        book = models.Book.objects.filter(pk=pk).first()
        # 2 序列化
        book_ser = serializer.BookModelSerializer(instance=book,data=request.data)
        # 3 判断合法性,并保存数据
        if book_ser.is_valid():
            book_ser.save()
            return Response(book_ser.data)
        else:
            return Response(book_ser.errors)

删除一条

class BookDetailAPIVIew(APIView):# 删除一条
    def delete(self,request,pk,*args,**kwargs):
        # 直接删除即可
        models.Book.objects.filter(pk=pk).delete()
        return Response({"msg":"删除成功!"})

GenericAPIView

 使用GenericAPIView写4个接口,GenericAPIView和APIView的区别就是,定义了query_set和serializer_class

删除接口和APIView一样

路由配置

urlpatterns = [
    path('book/', views.BookAPIView.as_view()),
    re_path('book/(?P<pk>\d+)', views.BookDetailAPIVIew.as_view()),

]

查询所有

class BookAPIView(GenericAPIView):
    queryset = models.Book.objects.all() # 建议带上 .object.all(),否则后面可能会报错
    serializer_class = serializer.BookModelSerializer
    # 查询所有
    def get(self,reuqest,*args,**kwargs):
        # 1 查询所有数据
        book_list = self.get_queryset()
        # 2 序列化
        book_ser = self.get_serializer(book_list,many=True)
        # 3 返回数据
        return Response(book_ser.data)

新增一条

class BookAPIView(GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer# 新增一条
    def post(self,request,*args,**kwargs):
        # 获取数据,并序列化
        book_ser = self.get_serializer(data=request.data)
        # 校验
        if book_ser.is_valid():
            # 保存数据
            book_ser.save()
            return Response(book_ser.data)
        else:
            return Response(book_ser.errors)

查询一条

class BookDetailAPIVIew(GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer
    def get(self,request,pk,*args,**kwargs):
        # 获取数据
        book = self.get_object() # 获取单条数据用get_object
        # 序列化
        book_ser = self.get_serializer(instance=book)
        # 返回数据
        return Response(book_ser.data)

修改一条

class BookDetailAPIVIew(GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializerdef put(self,request,*args,**kwargs):
        book = self.get_object()
        book_ser = self.get_serializer(instance = book,data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            return Response(book_ser.data)
        else:
            return Response(book_ser.errors)

删除一条

class BookDetailAPIVIew(GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializerdef delete(self,request,pk,*args,**kwargs):
        # models.Book.objects.filter(pk=pk).delete()
        self.get_object().delete()
        return Response({"msg":"删除成功"})

 GenericAPIView的5个扩展类

总共5个扩展类:

CreateModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin

使用的时候要结合GenericAPIVIew,因为这5个扩展类没有继承任何的类,就是一个基类,没有as_view方法,所以必须结合使用,建议将GenericAPIView写到第一个位置

基于GenericAPIView的5个扩展类,写上述5个接口

路由配置

urlpatterns = [
    path('book/', views.BookAPIView.as_view()),
    re_path('book/(?P<pk>\d+)', views.BookDetailAPIVIew.as_view()),

]

查询所有

class BookAPIView(GenericAPIView, ListModelMixin):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer

    # 查询所有
    def get(self, request, *args, **kwargs):
        return self.list(request)

新增一条

class BookAPIView(GenericAPIView, CreateModelMixin):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer# 新增一条
    def post(self, request, *args, **kwargs):
        return self.create(request)

查询一条

class BookDetailAPIVIew(GenericAPIView,RetrieveModelMixin):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer
    # 查询一条
    def get(self, request, pk, *args, **kwargs):
        return self.retrieve(request, pk)

更新一条

class BookDetailAPIVIew(GenericAPIView,RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer

# 修改一条
def put(self, request, pk, *args, **kwargs):
return self.update(request, pk)

删除一条

class BookDetailAPIVIew(GenericAPIView,RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer
# 删除一条
    def delete(self, request, pk, *args, **kwargs):
        return self.destroy(request, pk)

GenericAPIView的9个视图子类

来源

这9个视图子类是GenericAPIView结合GenericAPIView的5个扩展类,将get post put delete进一步封装得到的类,在使用时,只需要指定queryset和serializer_class即可

class ListAPIView(mixins.ListModelMixin, GenericAPIView): # 查询所有
class CreateAPIView(mixins.CreateModelMixin, GenericAPIView): # 新建一条
class DestroyAPIView(mixins.DestroyModelMixin, GenericAPIView): # 删除一条
class UpdateAPIView(mixins.UpdateModelMixin, GenericAPIView): # 修改一条
class ListCreateAPIView(mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView): # 查询所有、创建一条
class RetrieveAPIView(mixins.RetrieveModelMixin, GenericAPIView): # 查询一条
class RetrieveDestroyAPIView(mixins.RetrieveModelMixin, mixins.DestroyModelMixin, GenericAPIView): # 查询一条、删除一条
class RetrieveUpdateAPIView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, GenericAPIView): # 查询一条、修改一条
class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, GenericAPIView): # 查询一条、修改一条、删除一条

路由配置

urlpatterns = [
    path('book/', views.BookAPIView.as_view()),
    re_path('book/(?P<pk>\d+)', views.BookDetailAPIVIew.as_view()),

]

 

查询所有、新增一条

from rest_framework.generics import ListAPIView, CreateAPIView, DestroyAPIView, RetrieveAPIView, UpdateAPIView


class BookAPIView(ListAPIView, CreateAPIView): # 仅需要继承对应的类,不需要写get、post方法
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer

查询一条、修改一条、删除一条

from rest_framework.generics import ListAPIView, CreateAPIView, DestroyAPIView, RetrieveAPIView, UpdateAPIView
class BookDetailAPIVIew(DestroyAPIView, RetrieveAPIView, UpdateAPIView):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer

 

除了这5个常见的外,还有多个组合的,仅需要继承对应的类就可以了

视图集

来源

通过重写ViewSetMixin这个魔法类的as_view方法,重新定义了路由的写法,同时结合GenericAPIVie和其扩展类,写了视图集

ViewSetMixin(重写了as_view,提供了新的路由写法)

ViewSet(什么都没有,路由换了写法)

GenericViewSet(主要是继承了GenericAPIView)

ModelViewSet(方法是最全的,在路由写GenericAPIView的扩展类的方法名即可)

ReadOnlyModelViewSet(仅查询使用)

class ViewSetMixin: # 魔法类,重写了as_view方法,继承了这个类,那么路由就要写成这样:MyViewSet.as_view({'get': 'list', 'post': 'create'})

class ViewSet(ViewSetMixin, views.APIView): # 视图集基类,不提供任何方法,方法需要手动写,路由写法也是action:方法,写法类似于APIView,只不过路由是新写法

class GenericViewSet(ViewSetMixin, generics.GenericAPIView): # 路由是新写法,同时有了queryset、serializer_class

class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet): # 继承了GenericAPIView的5个扩展类,直接返回这5个扩展类的方法即可,同时继承了GenericViewSet

class ReadOnlyModelViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, GenericViewSet): # 继承了查询一条和所有的GenericAPIView的扩展类和GenericViewSet

通过ModelViewSet写5个接口

使用ModelViewSet的愿意是,这个类继承了GenericAPIView的扩展类,方法是最多的,实现相应的功能只需要在路由中写入对应即可

视图层

from rest_framework.viewsets import ModelViewSet


class BookAPIView(ModelViewSet):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer

路由层

带不带id值都可以写在一个视图类中,在路由层做区分即可

urlpatterns = [
    path('admin/', admin.site.urls),
    # 基础的视图类
    # path('book/', views.BookAPIView.as_view()),
    # re_path('book/(?P<pk>\d+)', views.BookDetailAPIVIew.as_view()),
    # 视图集合
    path('book/', views.BookAPIView.as_view(actions={'get': 'list', 'post': 'create'})),
    re_path('book/(?P<pk>\d+)', views.BookAPIView.as_view(actions={'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
]

 

posted @ 2022-01-04 14:10  hushowee  阅读(223)  评论(0)    收藏  举报