drf4

昨日回顾

1 序列化类
	-写一个类继承Serializer或者ModelSerializer
    -写字段(很多字段类),很多字段属性
    -视图类中:实例化得到一个对象:
    	-新增:data=字典
        -修改:instance,data
        -序列化:instance
   	-对象
    	-对象.data
        -对象.errors
        -对象.instacne
        
2 source
	-修改序列化后字典的key(字段名和source对应的名不能一样)
    -执行函数(直接连表操作)
    -可以.连表操作
3 SerializerMethodField
	-写在Serializer中
        publish = serializers.SerializerMethodField()
        def get_publish(self,obj):  # obj在models层中就相当于self,在Serializer中就是当前要序列化的对象
    -它不可以被反序列化
    	在Serializer中写两字段,一个作为序列化字段,一个作为反序列化字段(通过write_only和read_only控制)
        
4 ModelSerializer(用的多)
	-写一个类
    -写一个内部类
        class Meta:
            model=表模型
            fields='__all__'
            fields=['id','name']  # 这样写里面字段的类型是和models表里的字段类型一样,是映射过来的
            exclude=()  排除哪些字段
            read_only_field=[]
            extra_kwargs={'name':{'required':True}}
            depth=1
    -重写某些字段
    	-直接以fields中的某个字段为字段名,继续写即可
    -局部钩子,全局钩子
    
5 反序列化校验源码分析
6 many=True 源码分析
	-__new__和__init__和__call__
    	-对象() # 触发该对象类的__call__。一般是类(),因为类也是对象,所以会触发该类的父类的__call__
        
7 请求和响应
	-Request对象
    	-data
        -__getattr__
    -Response对象
    	-data
        -status
        -headers
    -通过配置实现前端只显示json格式
    	-在setting中全局配置
        -在视图类中局部配
        
    -drf有一套默认的配置文件,自己配置需要在settings.py中
    	REST_FRAMEWORK = {}
# 断言 assert a==1 如果这样写表示判断a==1成立时,才能通过,否则不通过,就跟if判断一样

今日内容

1 2个视图基类

# Django REST framwork 提供的视图的主要作用:
    控制序列化器的执行(检验、保存、转换数据)
    控制数据库查询的执行
# APIView:本身是继承了原生Django的View
# GenericAPIView:本身是继承了APIView,以下是在视图类中如果继承的是GenericAPIView时,内部所含有的属性和方法
	-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 app01 import models
from app01 import serializer
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
# 在路由中
path('books/', views.BookAPIView.as_view()),
re_path('^books/(?P<pk>\d+)', views.BookDetailAPIView.as_view()),

class BookAPIView(APIView):
    def get(self, request):  # 查询所有
        book_list = models.Book.objects.all()
        ser = serializer.BookModelSerializer(book_list, many=True)
        return Response(ser.data)

    def post(self, request):  # 新增一个
        ser = serializer.BookModelSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
        return Response('成功')

class BookDetailAPIView(APIView):
    def get(self, request, pk):  # 查询一个
        book = models.Book.objects.get(id=pk)
        ser = serializer.BookModelSerializer(book)
        return Response(ser.data)

    def put(self, request, pk):  # 修改一个
        book = models.Book.objects.get(id=pk)
        ser = serializer.BookModelSerializer(book, data=request.data)
        if ser.is_valid():
            ser.save()
        return Response('修改成功')

    def delete(self, request, pk):  # 删除一个
        models.Book.objects.filter(id=pk).delete()
        return Response('删除成功')
      
# 继承了GenericAPIView
class BookGenericView(GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer

    def get(self, request, *args, **kwargs):
        obj = self.get_queryset()  # 在此处调用的上面配置的查询所有
        ser = self.get_serializer(obj, many=True) #在此处调用的而是上面配置的序列化器 
        return Response(ser.data)
    def post(self, request, *args, **kwargs):
        ser=self.get_serializer(data=request.data)  #在此处调用的而是上面配置的序列化器 
        if ser.is_valid():
            ser.save()
        return Response('成功')

class BookDetailGenericAPIView(GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer

    def get(self, request, *args, **kwargs):
        obj = self.get_object()  # 拿出单个是调用get_object,前面路由分组必须是pk
        ser = self.get_serializer(obj)
        return Response(ser.data)

    def put(self, request, *args, **kwargs):
        obj = self.get_object()  # 拿出单个是调用get_object,前面路由分组必须是pk
        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() # 此处用到的上面配置的查询拿出所有,然后通过路由传过来的参数pk过滤单条数据
        return Response('删除成功')
# 由于上面封装了之后,里面的get,post,put,delete内部的代码都一样,因此只需要写成公共的方法提取出来,然后其他的类继承它,使用时直接调用就行了(以下是写的封装,实际上drf本身已经提供了封装的接口)
class ListView():
    def list(self,request, *args, **kwargs):
        obj = self.get_queryset()
        ser = self.get_serializer(obj, many=True)
        return Response(ser.data)

class CreateView():
    def create(self,request, *args, **kwargs):
        ser=self.get_serializer(data=request.data)
        if ser.is_valid():
            ser.save()
        return Response('成功')
    
class BookGenericView(GenericAPIView,CreateView,ListView):
    queryset = models.Book.objects.all()
    serializer_class = serializer.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)

2 5个视图扩展类

#5个视图扩展类(rest_framework.mixins)导入 from rest_framework.mixins import ListModelMixin, CreateModelMixin, DestroyModelMixin, RetrieveModelMixin, UpdateModelMixin ,下面右边是调用是调用的方法名
CreateModelMixin:create方法创建一条
DestroyModelMixin:destory方法删除一条
ListModelMixin:list方法获取所有
RetrieveModelMixin:retrieve获取一条
UpdateModelMixin:update修改一条
# 使用drf提供的5个视图扩展类
class BookGenericView(GenericAPIView,ListModelMixin,CreateModelMixin):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer
    
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs) # 调用的是ListModelMixin里的list,获取所有
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)  # 调用的是CreateModelMixin里的create,创建一条
    
class BookDetailGenericAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)  # 调用的是RetrieveModelMixin里的retrieve,获取一条

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs) # 调用的是UpdateModelMixin里的update,更新一条

    def delete(self, request, *args, **kwargs):  # 调用的是DestroyModelMixin里的delete,更新一条
        return self.destroy(request, *args, **kwargs)

3 9个子类视图

# 9个子类视图(rest_framework.generics)
CreateAPIView:继承CreateModelMixin,GenericAPIView,有post方法,新增数据
DestroyAPIView:继承DestroyModelMixin,GenericAPIView,有delete方法,删除数据
ListAPIView:继承ListModelMixin,GenericAPIView,有get方法获取所有
UpdateAPIView:继承UpdateModelMixin,GenericAPIView,有put和patch方法,修改数据
RetrieveAPIView:继承RetrieveModelMixin,GenericAPIView,有get方法,获取一条

ListCreateAPIView:继承ListModelMixin,CreateModelMixin,GenericAPIView,有get获取所有,post方法新增
RetrieveDestroyAPIView:继承RetrieveModelMixin,DestroyModelMixin,GenericAPIView,有get方法获取一条,delete方法删除
RetrieveUpdateAPIView:继承RetrieveModelMixin,UpdateModelMixin,GenericAPIView,有get获取一条,put,patch修改
RetrieveUpdateDestroyAPIView:继承RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView,有get获取一条,put,patch修改,delete删除
class CreateListGenericAPIView(GenericAPIView,CreateModelMixin,ListModelMixin):
    def get(self,request,*args,**kwargs):
        return self.list(request,*args,**kwargs)
    def post(self,request,*args,**kwargs):
        return  self.create(request,*args,**kwargs)
    
from rest_framework.generics import CreateAPIView,ListAPIView,ListCreateAPIView
from rest_framework.generics import UpdateAPIView,RetrieveAPIView,DestroyAPIView,RetrieveUpdateAPIView,RetrieveDestroyAPIView,RetrieveUpdateDestroyAPIView

# class BookGenericView(CreateAPIView):
# class BookGenericView(ListAPIView):
class BookGenericView(ListCreateAPIView):  # 只要继承drf中9个接口中的一个或者某几个,那么就可以拥有对应的方法,当请求过来后自动调用对应的方法,例如,如果发的是get请求就会自动触发对应的函数里的方法得到对应的结果而类中不用写get。
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer


# class BookDetailGenericAPIView(RetrieveAPIView):
# class BookDetailGenericAPIView(RetrieveAPIView,UpdateAPIView):
class BookDetailGenericAPIView(RetrieveUpdateDestroyAPIView):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer
# 此处还可以继承,虽然每一个类中可以有五个接口,但是还要写不同的类,于是到了视图集

4 视图集

# 在路由中   
path('books_set/', views.BookSetView.as_view({'get':'list','post':'create'})),
    # path('books_set/', views.BookSetView.as_view()), # 没有接受参数直接报错
re_path('^books_set/(?P<pk>\d+)', views.BookSetView.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
#在视图集中继承一个东西,能够有五个接口,可以不用将其放在不同的类中,导入from rest_framework.viewsets import ModelViewSet,只需要写一个视图类继承ModelViewSet,两条路由分开就可以,但是路由后面一定要接收参数,用于映射对应的方法。视图集中在执行as_view时是执行了ViewSetMixin里的as_view这个as_view是被重写,所以后面能够传参数,内部的actions用于接收
class BookSetView(ModelViewSet):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer

# ViewSet:     继承ViewSetMixin和APIView
# GenericViewSet:继承ViewSetMixin(一个魔法类,最重要的是重写了as_view,在as_view中多加了一个参数actions,所以上面传的参数{'get':'list','post':'create'}就给了actions,在actions内部,将字典循环,然后反射去执行最开始类中找对应的方法,由于最开始的类中继承了ModelViewSet,ModelViewSet继承了五个视图类,视图类中封装了对应的方法,然后就用setattr将其放在了最开始类的对象中,最终来了请求就会执行对应的方法), generics.GenericAPIView   
# ModelViewSet:继承mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,mixins.ListModelMixin,GenericViewSet     是五个视图扩展类和一个GenericViewSet
# ReadOnlyModelViewSet:继承mixins.RetrieveModelMixin,mixins.ListModelMixin,GenericViewSet  只能查所有和单条,其他全部不能使用

5 action的使用

# 只要继承了ViewSetMixin类,然后进行路由配置:path('books_mix/', views.BookView.as_view({'get':'lqz'})),视图类的方法中就会有个action
from rest_framework.viewsets import ViewSetMixin,ViewSet
class BookView(ViewSet):  # 此处的ViewSet继承了ViewSetMixin,此处也可写成继承ViewSetMixin和APIView
    def lqz(self,request,*args,**kwargs):
        print(self.action)   # 可以打印出函数名
        return Response('lqz')
# ViewSetMixin以后只要继承它,路由的配置就发生变化了,只需要写映射即可,里面写的函数可以写任意的名字和内容,而不在仅仅局限于增删改查那几个接口,当同时在一个视图类中写多个自定义的视图函数时,只需要在路由中新配置一个路径就好了,例如写login是post请求,一般会像上面类似的方法将其映射

7 路由的使用

# 自动生成路由
# SimpleRouter(用的比较多),DefaultRouter(会比SimpleRouter多两个跟路由,因此,可以访问跟路由)
# 继承了ViewSetMixin的视图类,以后写路由,可以自动生成,在urls.py中导入from rest_framework import routers
router = routers.SimpleRouter()  # 实例化得到一个对象
router.register('books', views.BookSetView,basename='book')  # 注册进路由,第一个参数是路径,第二个参数是视图类,第三个参数是别名,可以不写。可以注册多个直接在后面在复制一条,把参数改掉就可以了
# 把自动生成的路由配置到urlpatterns中,有两种方案
urlpatterns += router.urls  # 第一种配置,
re_path(r'', include(router.urls))  # 第二种配置如果要访问的是类似v1/books,那么前面的正则应该为v1/
   
# 配置路由的方式
	-最原始的
    	-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的路由生成的类似的路径是book/id/login,如果是False,是基于不带id的路由生成的类似于book/login
    	-@action(methods=['get'], detail=True)
from rest_framework.decorators import action   # 视图函数中导入
class BookSetView(ModelViewSet):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer
    # 类似于path('', views.BookSetView.as_view({'get': 'login'}))
    @action(methods=['get'], detail=True)
    def login(self,request,*args,**kwargs):
        print(args)
        print(kwargs)
        print(self.action)
        return Response('登录成功')

    @action(methods=['post'], detail=False)
    def lqz(self,request,*args,**kwargs):
        return Response('lqz')
posted @ 2020-11-20 18:44  feiguoguobokeyuan  阅读(139)  评论(0编辑  收藏  举报