zoukankan      html  css  js  c++  java
  • DRF中的Request


    2018-08-02 1. 内容回顾 1. Serializer(序列化) 1. ORM对应的query_set和ORM对象转换成JSON格式的数据 1. 在序列化类中定义自定义的字段:SerializerMethodField 在类中定义 get_自定义字段名(self, obj)方法 2. read_only 只在显示(查询)时才会有效。 2. 对前端POST过来的数据做有效性的校验 1. 一定要将数据以data=的形式传递到序列化类中!!! ser_obj = CommentSerializer(data=comment_data) 2. 判断数据是否有效 ser_obj.is_valid(): 欠一个源码 ser_obj.validated_data 中保存经过校验的有效数据 3. 局部钩子 定义一个validate_字段名(self, value) 4. 全局钩子 定义一个validate方法 3. .save()方法将符合要求的数据存入数据库 1. 本质上还是调用ORM的create()方法 类名.objects.create(**ser_obj.validated_data) 2. 超链接的序列化 1. 超连接字段的三个参数 # 文章超链接序列化 class ArticleHyperLinkedSerializer(serializers.HyperlinkedModelSerializer): # view_name参数 默认使用 表名-detail # lookup_url_kwarg参数 默认使用pk,指的是反向生成URL的时候 路由中的分组命名匹配的key # lookup_field参数 默认使用的pk, 指的是反向生成URL的时候, 路由中分组命名匹配的value school = serializers.HyperlinkedIdentityField( view_name='school-detail111', lookup_url_kwarg='name', lookup_field='school_name' ) 2. 想要生成完整的超链接API,在序列化的时候还要传入 context={'request': request} ser_obj = app01_serializers.ArticleHyperLinkedSerializer(all_article, many=True, context={'request': request}) 1. 想要生成相对路径 context={'request': None} 2. 今日内容 1. 面向对象的三大特性 1. 封装 1. 把共有的数据当成一类物体的属性 2. 把共有的功能当成一类物体的方法 2. 继承 1. 把共有的属性或方法抽离出来放到一个基类(父类)中 3. 多态 1. 不同的物体调用同一个方法有不同的效果 Python中数字的+和字符串的+ 2. 葫芦娃的故事 五个娃 ↓ 奇数娃和偶数娃 ↓ 套娃 3. GenericAPIView和五个混合类的组合使用 4. RetrieveUpdateDestroyAPIView和ListCreateAPIView的使用 5. ModelViewSet的使用 6. ModelViewSet Router的使用

      

    在Django REST Framework中内置的Request类扩展了Django中的Request类,实现了很多方便的功能--如请求数据解析和认证等。

    比如,区别于Django中的request从request.GET中获取URL参数,从request.POST中取某些情况下的POST数据。

    在APIView中封装的request,就实现了请求数据的解析:

    对于GET请求的参数我们通过request.query_params来获取。

    对于POST请求、PUT请求的数据我们通过request.data来获取。

    面向对象三大特性

    封装

    1. 把共有的数据当成一类物体的属性
    2. 把共有的功能当成一类物体的方法

    继承

    1. 把共有的属性或方法抽离出来放到一个基类(父类)中

    多态

    1. 不同的物体调用同一个方法有不同的效果
    比如:Python中数字的+和字符串的+,结果是不一样的。前者是计算,后者是拼接!

    葫芦娃的故事

    先来列举前5个娃,为啥是5个呢?到最后,你就知道了!

    """
    葫芦娃演示类的继承
    """
    
    
    class Wa1(object):
        name = '红娃'
    
        def f1(self):
            print('力大无穷!')
    
    
    class Wa2(object):
        name = '橙娃'
    
        def f2(self):
            print('千里眼顺风耳')
    
    
    class Wa3(object):
        name = '黄娃'
    
        def f3(self):
            print('钢筋铁骨!')
    
    
    class Wa4(object):
        name = '绿娃'
    
        def f4(self):
            print('喷火!')
    
    
    class Wa5(object):
        name = '青娃'
    
        def f5(self):
            print('喷水!')
    
    
    class CYM(Wa1, Wa3, Wa5):
        name = '奇数娃'
    
        def ff(self):
            print('我叫{},我会'.format(self.name))
            self.f1()
            self.f3()
            self.f5()
    
    
    class DBG(Wa2, Wa4):
        name = '偶数娃'
    
        def ff(self):
            print('我叫{},我会'.format(self.name))
            self.f2()
            self.f4()
    
    
    # a = CYM()
    # a.ff()
    #
    # b = DBG()
    # b.ff()
    
    
    # class NaNa(Wa1, Wa2, Wa3, Wa4, Wa5):
    #     name = '套娃'
    #
    #     def fff(self):
    #         print('我叫{},我会'.format(self.name))
    #         self.f1()
    #         self.f2()
    #         self.f3()
    #         self.f4()
    #         self.f5()
    #
    # c = NaNa()
    # c.fff()
    
    
    class SHE(CYM, DBG):
        name = '银白色的娃'
    
        def fff(self):
            print("我叫{},我会".format(self.name))
            self.f1()
            self.f2()
            self.f3()
            self.f4()
            self.f5()
    
    
    d = SHE()
    d.fff()
    

    奇数娃,它继承了一娃,三娃,五娃的技能

    偶数娃,它继承了二娃,四娃的技能

    套娃,它继承了奇数娃,偶数娃的技能。也就是说,它拥有5个娃的技能

    实例化3个角色,分别调用奇数娃,偶数娃,套娃的info方法

    完整代码如下:

    """
    葫芦娃演示类的继承
    """
    
    
    class Wa1(object):
        name = '红娃'
    
        def f1(self):
            print('力大无穷!')
    
    
    class Wa2(object):
        name = '橙娃'
    
        def f2(self):
            print('千里眼顺风耳')
    
    
    class Wa3(object):
        name = '黄娃'
    
        def f3(self):
            print('钢筋铁骨!')
    
    
    class Wa4(object):
        name = '绿娃'
    
        def f4(self):
            print('喷火!')
    
    
    class Wa5(object):
        name = '青娃'
    
        def f5(self):
            print('喷水!')
    
    
    class Jishuwa(Wa1,Wa3,Wa5):
        name = '奇数娃'
    
        def info(self):
            print("我是%s,我会:"%self.name)
            self.skill()
    
        def skill(self):    #技能
            self.f1()
            self.f3()
            self.f5()
    
    class Oushuwa(Wa2,Wa4):
        name = '偶数娃'
    
        def info(self):
            print("我是%s,我会:" % self.name)
            self.skill()
    
        def skill(self):    #技能
            self.f2()
            self.f4()
    
    class Taowa(Jishuwa,Oushuwa):
        name = '套娃'
    
        def info(self):
            print("我是{},我会:".format(self.name))
            self.skill()
    
        def skill(self):    #技能
            Jishuwa.skill(self)
            Oushuwa.skill(self)
    
    print('奇数娃'.center(20,'*'))
    role1 = Jishuwa()
    role1.info()
    
    print('偶数娃'.center(20,'*'))
    role2 = Oushuwa()
    role2.info()
    
    print('套娃'.center(20,'*'))
    role3 = Taowa()
    role3.info()
    面向对象-葫芦娃的故事

    执行输出:

    从结果上来看,可套娃是最牛B的!

    通过这个例子,慢慢来引申下面的内容。

    前提

    序列化

    修改app01(应用名)目录下的app01_serializers.py,完整代码如下:

    from app01 import models
    from rest_framework import serializers
    
    
    # 序列化评论的类
    class CommentSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Comment  # Comment表
            fields = "__all__"  # 序列化所有字段
            # 定义额外的参数
            extra_kwargs = {
                "content": {
                    "error_messages": {
                        "required": '内容不能为空',
                    }
                },
                "article": {
                    "error_messages": {
                        "required": '文章不能为空'
                    }
                }
            }
    
    
    # 学校的序列化
    class SchoolSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.School  # School表
            fields = "__all__"
    Views

    路由

    urls.py代码如下:

    1 from django.conf.urls import url,include
    2 from django.contrib import admin
    3 from app01 import app01_urls
    4 
    5 urlpatterns = [
    6     url(r'^admin/', admin.site.urls),
    7     url(r'api/', include(app01_urls)),
    8 ]
    urls.py 代码

     app01_urls.py代码如下:

    from django.conf.urls import url
    from app01 import views
    
    urlpatterns = [
        # 学校
        url(r'school/$', views.SchoolView.as_view()),
        url(r'school/(?P<pk>d+)/$', views.SchoolDetail.as_view()),
    ]
    

      

    初生牛犊之徒手垒代码阶段

    视图

    修改views.py,完整代码如下:

     1 from django.shortcuts import render, HttpResponse
     2 from app01 import models
     3 from rest_framework.views import APIView
     4 from app01 import app01_serializers  # 导入自定义的序列化
     5 from rest_framework.response import Response
     6 
     7 
     8 # Create your views here.
     9 
    10 class SchoolView(APIView):  # 所有记录
    11     def get(self, request, *args, **kwargs):  # GET请求
    12         queryset = models.School.objects.all()
    13         # 使用自定义序列化类。当返回结果不止一条时,要指定many=True参数
    14         serializers_class = app01_serializers.SchoolSerializer(queryset, many=True)
    15         return Response(serializers_class.data)
    16 
    17 
    18 class SchoolDetail(APIView):  # 单条记录
    19     def get(self, request, pk, *args, **kwargs):
    20         queryset = models.School.objects.filter(pk=pk).first()
    21         serializers_class = app01_serializers.SchoolSerializer(queryset)
    22         return Response(serializers_class.data)
    Views.py

    浏览器访问url:  http://127.0.0.1:8000/api/comment/

    效果如下:

    访问详情:http://127.0.0.1:8000/api/school/1/

    这个时候,需要增加评论表,它也需要上面2个功能:展示所有记录和单条记录

    将2个视图函数的代码复制一遍,修改表名和序列化类名

    from django.shortcuts import render, HttpResponse
    from app01 import models
    from rest_framework.views import APIView
    from app01 import app01_serializers # 导入自定义的序列化
    from rest_framework.response import Response


    # Create your views here.

    class SchoolView(APIView): # 所有记录
    def get(self, request, *args, **kwargs): # GET请求
    queryset = models.School.objects.all()
    # 使用自定义序列化类。当返回结果不止一条时,要指定many=True参数
    serializers_class = app01_serializers.SchoolSerializer(queryset, many=True)
    return Response(serializers_class.data)


    class SchoolDetail(APIView): # 单条记录
    def get(self, request, pk, *args, **kwargs):
    queryset = models.School.objects.filter(pk=pk).first()
    serializers_class = app01_serializers.SchoolSerializer(queryset)
    return Response(serializers_class.data)


    class CommentView(APIView): # 所有记录
    def get(self, request, *args, **kwargs): # GET请求
    queryset = models.Comment.objects.all()
    # 使用自定义序列化类。当返回结果不止一条时,要指定many=True参数
    serializers_class = app01_serializers.CommentSerializer(queryset, many=True)
    return Response(serializers_class.data)


    class CommentDetail(APIView): # 单条记录
    def get(self, request, pk, *args, **kwargs):
    queryset = models.Comment.objects.filter(pk=pk).first()
    serializers_class = app01_serializers.CommentSerializer(queryset)
    return Response(serializers_class.data)

    复制代码
    from django.shortcuts import render, HttpResponse
    from app01 import models
    from rest_framework.views import APIView
    from app01 import app01_serializers  # 导入自定义的序列化
    from rest_framework.response import Response
    
    
    # Create your views here.
    
    class SchoolView(APIView):  # 所有记录
        def get(self, request, *args, **kwargs):  # GET请求
            queryset = models.School.objects.all()
            # 使用自定义序列化类。当返回结果不止一条时,要指定many=True参数
            serializers_class = app01_serializers.SchoolSerializer(queryset, many=True)
            return Response(serializers_class.data)
    
    
    class SchoolDetail(APIView):  # 单条记录
        def get(self, request, pk, *args, **kwargs):
            queryset = models.School.objects.filter(pk=pk).first()
            serializers_class = app01_serializers.SchoolSerializer(queryset)
            return Response(serializers_class.data)
    
    
    class CommentView(APIView):  # 所有记录
        def get(self, request, *args, **kwargs):  # GET请求
            queryset = models.Comment.objects.all()
            # 使用自定义序列化类。当返回结果不止一条时,要指定many=True参数
            serializers_class = app01_serializers.CommentSerializer(queryset, many=True)
            return Response(serializers_class.data)
    
    
    class CommentDetail(APIView):  # 单条记录
        def get(self, request, pk, *args, **kwargs):
            queryset = models.Comment.objects.filter(pk=pk).first()
            serializers_class = app01_serializers.CommentSerializer(queryset)
            return Response(serializers_class.data)
    复制代码

    修改app01_urls.py,增加2个路径

    from django.conf.urls import url
    from app01 import views

    urlpatterns = [
    # 学校
    url(r'school/$', views.SchoolView.as_view()),
    url(r'school/(?P<pk>d+)/$', views.SchoolDetail.as_view()),
    # 评论
    url(r'comment/$', views.CommentView.as_view()),
    url(r'comment/(?P<pk>d+)/$', views.CommentDetail.as_view()),
    ]


    复制代码
    from django.conf.urls import url
    from app01 import views
    
    urlpatterns = [
        # 学校
        url(r'school/$', views.SchoolView.as_view()),
        url(r'school/(?P<pk>d+)/$', views.SchoolDetail.as_view()),
        # 评论
        url(r'comment/$', views.CommentView.as_view()),
        url(r'comment/(?P<pk>d+)/$', views.CommentDetail.as_view()),
    ]
    复制代码

    访问所有评论url:  http://127.0.0.1:8000/api/comment/

    访问单条评论url:    http://127.0.0.1:8000/api/comment/1/

     

    那么问题来了,再来一个表呢?再复制2个视图函数,修改表名和序列化类名?

    这不符合编程习惯,得需要将相同的代码,封装成一个类。那么其他表就可以继承了!

    那么接下来的GenericAPIView就展示了它强大的功能

    小试牛刀之使用混合类阶段

    GenericAPIView

    GenericAPIView对APIView再次封装,实现了强大功能:

    •   加入queryset属性,可以直接设置这个属性,不必再将实例的courses,再次传给seriliazer,系统会自动检测到。除此之外,可以重载get_queryset(),这样就不必设置‘queryset=* ’,这样就变得更加灵活,可以进行完全的自定义。
    • 加入serializer_class属性与实现get_serializer_class()方法。两者的存在一个即可,通过这个,在返回时,不必去指定某个serilizer
    • 设置过滤模版:filter_backends
    • 设置分页模版:pagination_class
    • 加入lookup_field="pk",以及实现了get_object方法:这个用得场景不多,但十分重要。他们两者的关系同理,要么设置属性,要么重载方法。他们的功能在于获取某一个实例时,指定传进来的后缀是什么。

    GenericAPIView的五个扩展类给我们提供了五个方法分别进行增删改查的不同操作,这样我们就不用写那么多函数

    五个扩展类(为啥是5个?答:增删改查,查有两个)

    搭配GenericAPIView使用

    1.ListModelMixin: 提供list方法快速实现列表视图(多条数据)

    2.CreateModelMixin: 提供create方法快速实现创建资源的视图

    3.RetrieveModelMixin 提供retrieve方法,可以快速实现返回一个存在的数据对象(需要传入pk)

    4.UpdateModelMixin 提供update方法,可以快速实现更新一个存在的数据对象。 提供partial_update方法,可以实现局部更新

    5.DestroyModelMixin 提供destroy方法,可以快速实现删除一个存在的数据对象

    注意:GenericAPIView不能单独使用,它需要和上面的5个扩展类配合使用才行

    源码分析,请参考文章:

    https://blog.csdn.net/u013210620/article/details/79869661

    ListModelMixin

    它返回数据列表,也就是多条数据

    使用时,需要导入模块

    from rest_framework.mixins import ListModelMixin

    RetrieveModelMixin 

    它负责单条数据的获取、更新、删除

    使用时,需要导入模块

    from rest_framework.mixins import RetrieveModelMixin

    举例:将上面4个视图函数改成GenericAPIView+ListModelMixin+RetrieveModelMixin

    使用前,需要导入模块

    from rest_framework.generics import GenericAPIView
    from rest_framework.mixins import ListModelMixin
    

    GenericAPIView只需要配置queryset和serializer_class   

    修改views.py,完整代码如下:

    from django.shortcuts import render,HttpResponse
    from app01 import models
    from rest_framework.views import APIView
    from app01 import app01_serialization       #导入自定义的序列化
    from rest_framework.response import Response
    from rest_framework.generics import GenericAPIView
    from rest_framework.mixins import ListModelMixin,RetrieveModelMixin
    
    class SchoolView(GenericAPIView,ListModelMixin):
        queryset = models.School.objects.all()
        serializer_class = app01_serialization.SchoolSerializer
    
        def get(self,request,*args,**kwargs):   #GET请求
            return self.list(request,*args,**kwargs)
    
    #RetrieveModelMixin 表示查询单条数据,需要传入pk参数
    class SchoolDetail(GenericAPIView,RetrieveModelMixin):
        queryset = models.School.objects.all()
        serializer_class = app01_serialization.SchoolSerializer
    
        def get(self,request,pk,*args,**kwargs): #GET请求
            return self.retrieve(request,pk,*args,**kwargs)
    
    class CommentView(GenericAPIView,ListModelMixin):
        queryset = models.Comment.objects.all()
        serializer_class = app01_serialization.CommentSerializer
    
        def get(self,request,*args,**kwargs):
            return self.list(request,*args,**kwargs)
    
    class CommentDetail(GenericAPIView,RetrieveModelMixin):
        queryset = models.Comment.objects.all()
        serializer_class = app01_serialization.CommentSerializer
    
        def get(self,request,pk,*args,**kwargs):
            return self.retrieve(request,pk,*args,**kwargs)

    访问不同的url,效果和上面是一样的!

    http://127.0.0.1:8000/api/comment/

    http://127.0.0.1:8000/api/comment/1/

    http://127.0.0.1:8000/api/school/

    http://127.0.0.1:8000/api/school/1/

    JsonResponse和Response的区别

    JsonResponse和Response都可以返回json对象。不同之处在于:

    使用Response时,如果是浏览器访问,就会返回一个页面,效果就是上面的图片。

    但是使用postman工具时,返回json数据,并不会有页面。

    而JsonResponse则没有这个功能,始终都是json对象

    CreateModelMixin

    它负责增加一条记录

    使用时,需要导入模块

    from rest_framework.mixins import CreateModelMixin

    举例:增加一条评论

    修改views.py,完整代码如下:

     1 from django.shortcuts import render, HttpResponse
     2 from app01 import models
     3 from rest_framework.views import APIView
     4 from app01 import app01_serializers  # 导入自定义的序列化
     5 from rest_framework.response import Response
     6 from rest_framework.generics import GenericAPIView
     7 from rest_framework.mixins import ListModelMixin, RetrieveModelMixin,CreateModelMixin
     8 
     9 
    10 # Create your views here.
    11 
    12 class SchoolView(GenericAPIView, ListModelMixin):
    13     queryset = models.School.objects.all()
    14     serializer_class = app01_serializers.SchoolSerializer
    15 
    16     def get(self, request, *args, **kwargs):  # GET请求
    17         return self.list(request, *args, **kwargs)
    18 
    19 
    20 # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
    21 class SchoolDetail(GenericAPIView, RetrieveModelMixin):
    22     queryset = models.School.objects.all()
    23     serializer_class = app01_serializers.SchoolSerializer
    24 
    25     def get(self, request, pk, *args, **kwargs):  # GET请求
    26         return self.retrieve(request, pk, *args, **kwargs)
    27 
    28 
    29 class CommentView(GenericAPIView, ListModelMixin,CreateModelMixin):
    30     queryset = models.Comment.objects.all()
    31     serializer_class = app01_serializers.CommentSerializer
    32 
    33     def get(self, request, *args, **kwargs):  # GET请求
    34         return self.list(request, *args, **kwargs)
    35 
    36     def post(self, request, *args, **kwargs):  # POST请求
    37         return self.create(request, *args, **kwargs)
    38 
    39 
    40 # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
    41 class CommentDetail(GenericAPIView, RetrieveModelMixin):
    42     queryset = models.Comment.objects.all()
    43     serializer_class = app01_serializers.CommentSerializer
    44 
    45     def get(self, request, pk, *args, **kwargs):  # GET请求
    46         return self.retrieve(request, pk, *args, **kwargs)
    Views.py

    json数据

    {
        "content": "噗嗤",
        "article": 2
    }

    指定格式为JSON

    查看返回结果,它会增加的数据

    查看app01_comment表

     

    DestroyModelMixin

     删除单条数据

    使用时,需要导入模块

    from rest_framework.mixins import DestroyModelMixin

    举例:删除一条评论,那么在删除之前,可以打印一句话

     1 from django.shortcuts import render, HttpResponse
     2 from app01 import models
     3 from rest_framework.views import APIView
     4 from app01 import app01_serializers  # 导入自定义的序列化
     5 from rest_framework.response import Response
     6 from rest_framework.generics import GenericAPIView
     7 from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
     8 from rest_framework.mixins import CreateModelMixin, DestroyModelMixin
     9 
    10 # Create your views here.
    11 
    12 class SchoolView(GenericAPIView, ListModelMixin):
    13     queryset = models.School.objects.all()
    14     serializer_class = app01_serializers.SchoolSerializer
    15 
    16     def get(self, request, *args, **kwargs):  # GET请求
    17         return self.list(request, *args, **kwargs)
    18 
    19 
    20 # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
    21 class SchoolDetail(GenericAPIView, RetrieveModelMixin):
    22     queryset = models.School.objects.all()
    23     serializer_class = app01_serializers.SchoolSerializer
    24 
    25     def get(self, request, pk, *args, **kwargs):  # GET请求
    26         return self.retrieve(request, pk, *args, **kwargs)
    27 
    28 
    29 class CommentView(GenericAPIView, ListModelMixin,CreateModelMixin):
    30     queryset = models.Comment.objects.all()
    31     serializer_class = app01_serializers.CommentSerializer
    32 
    33     def get(self, request, *args, **kwargs):  # GET请求
    34         return self.list(request, *args, **kwargs)
    35 
    36     def post(self, request, *args, **kwargs):  # POST请求
    37         return self.create(request, *args, **kwargs)
    38 
    39 
    40 # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
    41 class CommentDetail(GenericAPIView, RetrieveModelMixin,DestroyModelMixin):
    42     queryset = models.Comment.objects.all()
    43     serializer_class = app01_serializers.CommentSerializer
    44 
    45     def get(self, request, pk, *args, **kwargs):  # GET请求
    46         return self.retrieve(request, pk, *args, **kwargs)
    47 
    48     def delete(self, request, pk, *args, **kwargs):  # DELETE请求
    49         return self.destroy(request, pk, *args, **kwargs)
    50 
    51     def perform_destroy(self, instance):
    52         print("你真的真的确定要删除了吗?...")
    53         instance.delete()
    Views.py

    使用postman发送delete请求,注意:数字后面一定要有 / ,否则不没有效果

    因为路由规则定义,必须以 / 结尾!

    它的返回结果为空

    查看Pycharm控制台输出:

    你真的真的确定要删除了吗?...

    UpdateModelMixin

    更新单条数据

    使用时,需要导入模块

    from rest_framework.mixins import UpdateModelMixin

    举例:更新一条评论

    举例:更新一条评论

    from django.shortcuts import render, HttpResponse
    from app01 import models
    from rest_framework.views import APIView
    from app01 import app01_serializers # 导入自定义的序列化
    from rest_framework.response import Response
    from rest_framework.generics import GenericAPIView
    from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
    from rest_framework.mixins import CreateModelMixin, DestroyModelMixin,UpdateModelMixin

    # Create your views here.

    class SchoolView(GenericAPIView, ListModelMixin):
    queryset = models.School.objects.all()
    serializer_class = app01_serializers.SchoolSerializer

    def get(self, request, *args, **kwargs): # GET请求
    return self.list(request, *args, **kwargs)


    # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
    class SchoolDetail(GenericAPIView, RetrieveModelMixin):
    queryset = models.School.objects.all()
    serializer_class = app01_serializers.SchoolSerializer

    def get(self, request, pk, *args, **kwargs): # GET请求
    return self.retrieve(request, pk, *args, **kwargs)


    class CommentView(GenericAPIView, ListModelMixin,CreateModelMixin):
    queryset = models.Comment.objects.all()
    serializer_class = app01_serializers.CommentSerializer

    def get(self, request, *args, **kwargs): # GET请求
    return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs): # POST请求
    return self.create(request, *args, **kwargs)


    # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
    class CommentDetail(GenericAPIView, RetrieveModelMixin,DestroyModelMixin,UpdateModelMixin):
    queryset = models.Comment.objects.all()
    serializer_class = app01_serializers.CommentSerializer

    def get(self, request, pk, *args, **kwargs): # GET请求
    return self.retrieve(request, pk, *args, **kwargs)

    def delete(self, request, pk, *args, **kwargs): # DELETE请求
    return self.destroy(request, pk, *args, **kwargs)

    def perform_destroy(self, instance):
    print("你真的真的确定要删除了吗?...")
    instance.delete()

    def put(self, request, pk, *args, **kwargs): # PUT请求
    return self.update(request, pk, *args, **kwargs)


    复制代码
    from django.shortcuts import render, HttpResponse
    from app01 import models
    from rest_framework.views import APIView
    from app01 import app01_serializers  # 导入自定义的序列化
    from rest_framework.response import Response
    from rest_framework.generics import GenericAPIView
    from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
    from rest_framework.mixins import CreateModelMixin, DestroyModelMixin,UpdateModelMixin
    
    # Create your views here.
    
    class SchoolView(GenericAPIView, ListModelMixin):
        queryset = models.School.objects.all()
        serializer_class = app01_serializers.SchoolSerializer
    
        def get(self, request, *args, **kwargs):  # GET请求
            return self.list(request, *args, **kwargs)
    
    
    # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
    class SchoolDetail(GenericAPIView, RetrieveModelMixin):
        queryset = models.School.objects.all()
        serializer_class = app01_serializers.SchoolSerializer
    
        def get(self, request, pk, *args, **kwargs):  # GET请求
            return self.retrieve(request, pk, *args, **kwargs)
    
    
    class CommentView(GenericAPIView, ListModelMixin,CreateModelMixin):
        queryset = models.Comment.objects.all()
        serializer_class = app01_serializers.CommentSerializer
    
        def get(self, request, *args, **kwargs):  # GET请求
            return self.list(request, *args, **kwargs)
    
        def post(self, request, *args, **kwargs):  # POST请求
            return self.create(request, *args, **kwargs)
    
    
    # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
    class CommentDetail(GenericAPIView, RetrieveModelMixin,DestroyModelMixin,UpdateModelMixin):
        queryset = models.Comment.objects.all()
        serializer_class = app01_serializers.CommentSerializer
    
        def get(self, request, pk, *args, **kwargs):  # GET请求
            return self.retrieve(request, pk, *args, **kwargs)
    
        def delete(self, request, pk, *args, **kwargs):  # DELETE请求
            return self.destroy(request, pk, *args, **kwargs)
    
        def perform_destroy(self, instance):
            print("你真的真的确定要删除了吗?...")
            instance.delete()
    
        def put(self, request, pk, *args, **kwargs):  # PUT请求
            return self.update(request, pk, *args, **kwargs)
    复制代码

    json数据

    {
        "id": 6,
        "content": "从前的日色变得慢",
        "article": 1
    }

    使用put发送,选择JSON

    如果返回结果是:

    415(Unsupported Media Type)不支持的类型异常

    请查看Headers,一定要勾选

    再次发送,查看返回结果

    查看表app01_comment,发现记录更新了!

     

    牛气冲天之使用通用类

    Django REST framework提供了9个通用视图,详情请参考以下链接中的《混凝土视图类》

    https://www.cnblogs.com/yangxiaoling/p/6914880.html

    RetrieveUpdateDestroyAPIView

    用于读写删除端点来表示单个模型实例

    提供getputpatchdelete方法处理。

    扩展:GenericAPIViewRetrieveModelMixinUpdateModelMixinDestroyModelMixin

    它相当于上面葫芦娃例子中的奇数娃

    使用需要导入模块

    from rest_framework.generics import RetrieveUpdateDestroyAPIView

    举例:将CommentDetail改造成RetrieveUpdateDestroyAPIView

    它拥有get,put,patch和delete方法处理,所以之前的那些方法,都可以干掉了!

    测试GET

    测试POST,注意后面没有数字

    查看返回结果

    查看表app01_comment,发现多了一条记录

    牛牛牛牛之使用视图集

    ModelViewSet

    ModelViewSet视图集会自动提供list,create, retrieve, update & destroy这些行为,

    查看源代码:它有6个功能

    也就说它具有5个葫芦娃的能力,也就是上面面向对象讲到的套娃

    使用时,需要导入模块

    from rest_framework.viewsets import ModelViewSet

    处理器方法只有在定义了URLConf的时候才会绑定这些行为。 
    在urls.py文件中,我们把ViewSet绑定到一些具体的视图上

    修改app01_urls.py

    from django.conf.urls import url
    from app01 import views
    
    urlpatterns = [
        # 学校
        url(r'school/$', views.SchoolView.as_view()),
        url(r'school/(?P<pk>d+)/$', views.SchoolDetail.as_view()),
    
        # 评论
        url(r'comment/$', views.CommentViewSet.as_view({
            'get': "list",
            'post': 'create'
        })),
    
        url(r'comment/(?P<pk>d+)/$', views.CommentViewSet.as_view({
            'get': 'retrieve',
            'put': 'update',
            'delete': 'destroy'
        })),
    ]
    

    参数解释:

    get, post , put , delete分别表示不同的请求方式

    后面对应的值分别是ListModelMixin,

    CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin

    修改views.py,增加一个视图函数,注释多余的代码

    from django.shortcuts import render, HttpResponse
    from app01 import models
    from rest_framework.views import APIView
    from app01 import app01_serializers  # 导入自定义的序列化
    from rest_framework.response import Response
    from rest_framework.generics import GenericAPIView,RetrieveUpdateDestroyAPIView,ListCreateAPIView
    from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
    from rest_framework.mixins import CreateModelMixin, DestroyModelMixin,UpdateModelMixin
    from rest_framework.viewsets import ModelViewSet
    
    # Create your views here.
    
    class SchoolView(GenericAPIView, ListModelMixin):
        queryset = models.School.objects.all()
        serializer_class = app01_serializers.SchoolSerializer
    
        def get(self, request, *args, **kwargs):  # GET请求
            return self.list(request, *args, **kwargs)
    
    
    # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
    class SchoolDetail(GenericAPIView, RetrieveModelMixin):
        queryset = models.School.objects.all()
        serializer_class = app01_serializers.SchoolSerializer
    
        def get(self, request, pk, *args, **kwargs):  # GET请求
            return self.retrieve(request, pk, *args, **kwargs)
    
    
    # class CommentView(ListCreateAPIView):
    #     queryset = models.Comment.objects.all()
    #     serializer_class = app01_serializers.CommentSerializer
    #
    #
    # class CommentDetail(RetrieveUpdateDestroyAPIView):
    #     queryset = models.Comment.objects.all()
    #     serializer_class = app01_serializers.CommentSerializer
    
    class CommentViewSet(ModelViewSet):
        queryset = models.Comment.objects.all()
        serializer_class = app01_serializers.CommentSerializer
    

    一个视图函数,就搞定了5种请求方式,惊叹不已!

    测试GET

    后面的几种请求方式,大家可以自行测试!

    再来一牛之高级路由

    视图

     同上,还是使用ModelViewSet

    路由

    因为我们正在使用ViewSet代替View,实际上已经不再需要自己来设计URL的配置了。将资源和视图、URL绑定到一起是一个可以自动完成的过程,只需要使用Router即可。我们需要做的就是将视图集注册到Router上去而已。 

    修改app01_urls.py

    from django.conf.urls import url
    from app01 import views
    
    urlpatterns = [
        # 学校
        url(r'school/$', views.SchoolView.as_view()),
        url(r'school/(?P<pk>d+)/$', views.SchoolDetail.as_view()),
    
        # 评论
        # url(r'comment/$', views.CommentViewSet.as_view({
        #     'get': "list",
        #     'post': 'create'
        # })),
        # 
        # url(r'comment/(?P<pk>d+)/$', views.CommentViewSet.as_view({
        #     'get': 'retrieve',
        #     'put': 'update',
        #     'delete': 'destroy'
        # })),
    ]
    
    from rest_framework.routers import DefaultRouter
    
    router = DefaultRouter()
    # 注册路由,表示路径comment对应视图函数CommentViewSet
    router.register(r'comment', views.CommentViewSet)
    urlpatterns += router.urls
    

    将ViewSets 注册到Router的过程实际上类似于提供一个urlpattern。我们引入了两个参数,一个是views的URL prefix,另一个是viewset本身。

    我们使用DefaultRouter 也会自动的帮我们创建API root视图,多余路由可以注销掉了。

    赠图一张,祝君好运

    二、django logging配置

    做开发开不开日志,以下是我在工作中写Django项目常用的logging配置。

    配置

    修改settings.py,最后一行添加

    # 日志相关配置
    LOGGING = {
        'version': 1,  # 保留字段
        'disable_existing_loggers': False,  # 不要禁用已经存在的logger实例
    
        'formatters': {  # 定义三种日志显示的格式
            'standard': {
                'format': '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]'
                          '[%(levelname)s][%(message)s]'
            },
            'simple': {
                'format': '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
            },
            'collect': {
                'format': '%(message)s'
            }
        },
    
        'filters': {  # 定义一个过滤规则
            'require_debug_true': {
                '()': 'django.utils.log.RequireDebugTrue',
            },
        },
    
        'handlers': {  # 日志流的处理方式
            'console': {  # 把日志打印到终端
                'level': 'DEBUG',
                'filters': ['require_debug_true'],  # 只有在Django debug为True时才在屏幕打印日志
                'class': 'logging.StreamHandler',
                'formatter': 'simple'
            },
            'default': {
                'level': 'INFO',
                'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自动切
                'filename': os.path.join(BASE_LOG_DIR, "info.log"),  # 日志文件
                'maxBytes': 1024 * 1024 * 500,  # 日志大小 500M
                'backupCount': 3,  #
                'formatter': 'standard',
                'encoding': 'utf-8',
            },
            'error': {
                'level': 'ERROR',
                'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自动切
                'filename': os.path.join(BASE_LOG_DIR, "err.log"),  # 日志文件
                'maxBytes': 1024 * 1024 * 500,  # 日志大小 500M
                'backupCount': 5,
                'formatter': 'standard',
                'encoding': 'utf-8',
            },
            'collect': {
                'level': 'INFO',
                'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自动切
                'filename': os.path.join(BASE_LOG_DIR, "collect.log"),
                'maxBytes': 1024 * 1024 * 500,  # 日志大小 500M
                'backupCount': 5,
                'formatter': 'collect',
                'encoding': "utf-8"
            }
        },
        'loggers': {
    
           # 默认的logger应用如下配置
            '': {
                'handlers': ['default', 'console', 'error'],  # 上线之后可以把'console'移除
                'level': 'DEBUG',
                'propagate': True,  # 是否向父级logger实例传递日志信息
            },
    
            # 名为 'collect'的logger还单独处理
            'collect': {
                'handlers': ['console', 'collect'],
                'level': 'INFO',
            }
        },
    }
    

    使用

    在视图函数中使用时,先导入模块,并声明变量

    import logging
    # 生成一个以当前文件名为名字的 logger实例
    logger = logging.getLogger(__name__)
    # 生成一个名字为collect的日志实例
    collect_logger = logging.getLogger('collect')
    

    然后在逻辑代码中加入

    logger.warning('找不到记录...')
    或者
    collect_logger.info(name)

    Python logger流示图

    附:Python logger流示图

    三、django-debug-toolbar使用指南

    介绍

    django-debug-toolbar 是一组可配置的面板,可显示有关当前请求/响应的各种调试信息,并在单击时显示有关面板内容的更多详细信息。

    github地址

    文档地址

    安装

    pip3 install django-debug-toolbar

    配置

    1. settings.py中

    将 debug_toolbar 添加到 INSTALL_APPS 中,最后一行添加

    INSTALLED_APPS = [
        …
        'debug_toolbar',
    ]
    

    2. urls.py中

    1 from django.conf import settings
    2 from django.conf.urls import include, url
    3 
    4 if settings.DEBUG:
    5     import debug_toolbar
    6     urlpatterns = [
    7         url(r'^__debug__/', include(debug_toolbar.urls)),
    8     ] + urlpatterns
    urls.py

    3. settings.py中

    在中间件中加入DebugToolbarMiddleware,最后一行添加

    MIDDLEWARE = [
        # ...
        'debug_toolbar.middleware.DebugToolbarMiddleware',
    ]
    

    4.加入 INTERNAL_IPS

    如果是本机调试,还在将127.0.0.1加入 INTERNAL_IPS

    在settings.py中加入以下配置项:

    INTERNAL_IPS = ['127.0.0.1', ]

    5.  配置jQuery的URL

    django-debug-toolbar 默认使用的是Google的地址,默认配置如下:

    JQUERY_URL = '//ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js'

    国内用不了的话可以在settings.py中配置一下,例如(我这里特意选用了和原作者相同版本的jQuery):

    修改settings.py,最后一行添加

    DEBUG_TOOLBAR_CONFIG = {
        "JQUERY_URL": '//cdn.bootcss.com/jquery/2.2.4/jquery.min.js',
    }

    或者你如果在Django项目中使用了jquery的话就可以直接将这一项置为空,那么django-debug-toolbar 就会使用你项目中用到的jquery:

    DEBUG_TOOLBAR_CONFIG = {
        "JQUERY_URL": '',
    }

    使用

    访问具体路径的时候在页面右侧有各项配置面板,点击即可查看各种调试信息。

      

      

      

      

      

      

      

  • 相关阅读:
    后端框架:SpringBoot+Mybatis+Dubbox(zookeeper+dubbo-admin)
    java代码执行mysql存储过程
    SpringBoot整合Junit
    摘要算法之MD5
    java如何控制下载的文件类型是txt还是doc?如何将文件名返回给前端?Content-disposition
    Android Atuido 连接模拟器
    verilog CRC 校验
    Altium Designer(AD软件)如何导出gerber文件
    SpringBoot集成mybatisplus
    C++ | 通过智能指针实现资源管理
  • 原文地址:https://www.cnblogs.com/haowen980/p/9409437.html
Copyright © 2011-2022 走看看