zoukankan      html  css  js  c++  java
  • drf4

    s7day131

    今日内容概要:

    1. 分页

      越往后翻,越慢的问题

      (分页页数少, 展示少, 上下页, 减少页数)

    2. 视图

    3. 路由

    4. 渲染

    5. django组件: content-type

    内容回顾:

    1.rest规范

    • 请求是一类:

      ​ https 域名 版本 资源(名词) 过滤

      请求头: method

      响应:

      ​ 状态码 出错 结果集 Hypermedia API

    2.rest framework

    • django请求生命周期

      view dispatch 封装request initial(认证,权限,节流)

      版本: url 请求头 spacename (一般url)

      反射到视图函数: 拿数据:序列化,解析器不同

      Django中: (drf中有解析器不会这样)

      request.body中有值, post没有值? 传请求体了, contype=url_encode

      数据格式: a=b&c=d...这两个条件

      字段(Charfield()), method(get_) , url(hey....)

      many=True , ser.data

    • 要求: 前4个组件(源码)

    • 序列化

    6期师兄:

    ​ 韧劲. 兵哥哥 . 学了个安卓, 中软(和华为的工作), 被裁掉了
    ​ 去上海找,(问源码会不会?不会!) (我允许自己学不会) 6.30上自习, 就两天不在教室, 一直到最后, 过年回家没有干别的, 也在看视频(学习)

    解析器

    返回属性和返回方法的

    """
    many=True , 执行ListSerializer对象 的构造方法
    many = flase , 执行UserInfoSerializer对象 的构造方法
    """
    ser = UserInfoSerializer(instance=users, many=True, context={'request': request})  #根据id 反向生成 url  # [{"id": 1, "username": "liu", "password": "123", "group": "http://127.0.0.1:8000/app01/v2/group/1", "roles": [1, 2, 3]},
    print(ser)
    
    Serializer
    BaseSerializer
      def __new__(cls, *args, **kwargs):
            # We override this method in order to automagically create
            # `ListSerializer` classes instead when `many=True` is set.
            if kwargs.pop('many', False):       # 没有many就是false
                # many = True , 对queryset进行 处理
                return cls.many_init(*args, **kwargs)
            # many = False 对对象进行处理  返回一个对象实例化的 构造方法 instance
            return super().__new__(cls, *args, **kwargs)
      @classmethod
      def many_init(cls, *args, **kwargs):	
          list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer)        
    
    ## 执行这里的构造方法
    class ListSerializer(BaseSerializer):
      def __init__(self, *args, **kwargs):
            print('构造方法')
    
    def data(self):
        ret = super().data
        return ReturnList(ret, serializer=self)
    
    def data():
        if not hasattr(self, '_data'):
            if self.instance is not None and not getattr(self, '_errors', None):
                self._data = self.to_representation(self.instance)
    

    ListSerializer源码下的

    def to_representation(self, data):
        """
        List of object instances -> List of dicts of primitive datatypes.
        """
        # Dealing with nested relationships, data can be a Manager,
        # so, first get a queryset from the Manager if needed
        iterable = data.all() if isinstance(data, models.Manager) else data
    
        return [
            self.child.to_representation(item) for item in iterable
        ]
    
    def to_representation(self, instance):
        """
        Object instance -> Dict of primitive datatypes.
        """
        ret = OrderedDict()
        fields = self._readable_fields
    
        for field in fields:
            try:
                # CharField.get_attribute(对象) # 对象.username
                attribute = field.get_attribute(instance)
            except SkipField:
                continue
    
            # We skip `to_representation` for `None` values so that fields do
            # not have to explicitly deal with that case.
            #
            # For related fields with `use_pk_only_optimization` we need to
            # resolve the pk value.
            check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
            if check_for_none is None:
                ret[field.field_name] = None
            else:
                """
                {
                id:1,   CharField
                pwd:123,    CharField
                group:obj   HyperlinkedIdentityField
                } 
                """
                ret[field.field_name] = field.to_representation(attribute)
    
    class HyperlinkedIdentityField(HyperlinkedRelatedField):
    
    没有去父类中找
    
    class HyperlinkedRelatedField(RelatedField):
    
    def to_representation(self, value):
        try:			# value 对象, 对象反射取值
            url = self.get_url(value, self.view_name, request, format)
    
    def get_url(self, obj, view_name, request, format):
    	lookup_value = getattr(obj, self.lookup_field)
    
    lookup_field
            self.lookup_field = kwargs.pop('lookup_field', self.lookup_field)
    
    

    所以

    group = serializers.HyperlinkedIdentityField(view_name='gp', lookup_field='group_id', lookup_url_kwarg='pk') # id 反向生成url , 给起个名

    get_url中:
    	lookup_value = getattr(obj, self.lookup_field)
        kwargs = {self.lookup_url_kwarg: lookup_value}
        # {xxx:1}
        # reverse(view_name='gp')
        return self.reverse(view_name, kwargs=kwargs, request=request, format=format)
    # 还有返回url的步骤
    
    self.lookup_url_kwarg = kwargs.pop('lookup_url_kwarg', self.lookup_field)
    
            {
            id:1,   CharField
            pwd:123,    CharField
            group:obj  ->group:http://group/1
            } 
    

    小bug的source 反向

    value = self.to_internal_value(data)
    

    验证源码

    # 钩子函数自定义验证规则                                                                   # 以什么开头
        def validate_title(self, value):
            print(value)
            from rest_framework import exceptions
            raise exceptions.ValidationError('看你不顺眼')
            return value
    
       for field in fields:
                # validate_字段名
                validate_method = getattr(self, 'validate_' + field.field_name, None)
                primitive_value = field.get_value(data)
                try:
                    # 执行字段本身的正则
                    validated_value = field.run_validation(primitive_value)
                    if validate_method is not None:
                        # 验证的钩子方法
                        validated_value = validate_method(validated_value)
    

    1.分页

    a.分页, 看第n页, 每页显示n条数据;

    b.分页, 在第n个位置, 向后查看n条数据

    c.加密分页(上一页和下一页) : 速度也不慢(本质上:第一页的最大id和最小id记住,大于,不扫描)

    a.分页, 看第n页, 每页显示n条数据;

    class PageNumberPagination(BasePagination):	
    	page_query_param = 'page'
    	所以访问http://127.0.0.1:8000/app01/v2/page1/?page=2
    
    自定制分页 继承它
    from rest_framework.pagination import PageNumberPagination
    
    class MyPageNumberPagination(PageNumberPagination):
        page_size = 2
        page_size_query_param = 'size'   # 合上面的是一体的
        max_page_size = None
    
        page_query_param = 'page'  # 页码
        
        
    

    http://127.0.0.1:8000/app01/v2/page1/?page=2&size=3

    [
        {
            "id": 4,
            "title": "张三"
        },
        {
            "id": 5,
            "title": "李四"
        },
        {
            "id": 6,
            "title": "王五"
        }
    
    class Pager1View(APIView):
        def get(self, request, *args, **kwargs):
            # 获取所有数据
            roles = models.Role.objects.all()
            ser = PagerSerialiser(instance=roles, many=True)
            ret = json.dumps(ser.data, ensure_ascii=False)
            # return HttpResponse(ret)
    
            # 创建分页对象
            pg = MyPageNumberPagination()
    
            # 在数据中获取分页的数据
            pager_roles = pg.paginate_queryset(queryset=roles, request=request, view=self)
    
            # 分页
            print(pager_roles)  # [<Role: Role object>, <Role: Role object>]  2个对象
    
            # 对数据进行序列化
            ser = PagerSerialiser(instance=pager_roles, many=True)        
        
            # return Response(ser.data)   #  返回数据  
            return pg.get_paginated_response(ser.data)  # 上一页下一页也给做了 
    

    b.分页, 在第n个位置, 向后查看n条数据

    class MyPageNumberPagination(LimitOffsetPagination):
        default_limit = 2
        limit_query_param = 'limit'
        offset_query_param = 'offset'
        max_limit = 5
    

    换个继承的类,修改数据

         # 创建分页对象
            pg = MyPageNumberPagination()
            # pg = LimitOffsetPagination()
    

    c.加密分页

    (上一页和下一页) : 速度也不慢(本质上:第一页的最大id和最小id记住,大于,不扫描)

    class MyPageNumberPagination(CursorPagination):
        cursor_query_param = 'cursor'
        page_size = 2
        ordering = 'id'  # 按id排序
        page_size_query_param = None
        max_page_size = None
    

    http://127.0.0.1:8000/app01/v2/page1/

    "next": "http://127.0.0.1:8000/app01/v2/page1/?cursor=cD00",
    

    部分源码

    # current_position : id 前后处理, 比较方便,比较两个
    if self.cursor.reverse != is_reversed:
    kwargs = {order_attr + '__lt': current_position}
    else:
    kwargs = {order_attr + '__gt': current_position}
    

    先讲渲染

    首先settings

    INSTALLED_APPS = [    'rest_framework',]
    
    # 渲染器
    from rest_framework.response import Response
    

    分页总结:

    放到mysql中:

    设计表结构

    连表查询(基础)

    1. 数据量大的话,如何做分页?

      最大值,最小值(有重合的点都要说出来,边缘的点)

      问一个答一个,失败率非常高,每一个简历对应的都有答案(必须会)

    2. 临时想到的题? 最近在看的题? 你怎么办?django如果没有中间件怎么办?

    3. 主动? 你自己说 80你会, 而不是他一直在问,一直不会

    数据库性能相关? 索引

    ​ 没问你, 你要说, 再看drf,数据大的时候,怎么样 , drf分页挺好的,
    ​ 根据最大值,最小值,.处理, 但是数据大的时候,一样慢, 他又把页数做了个加密.挺好
    ​ 上一页,下一页,这样

    带到你会的领域

    2.视图

    a.过去

    ​ class PagePager1View(View):

    ​ pass

    b. 现在

    ​ class Pager1View(APIView): # view

    ​ pass

    c. 无用

    又继承了APIView(三层继承) , 里面封装了方法, 但是还是用的

    # 提供了许多方法
    from rest_framework.generics import GenericAPIView
    class View1View(GenericAPIView):
        queryset = models.Role.objects.all()
        serializer_class = PagerSerialiser
        pagination_class = PageNumberPagination
    
        def get(self, request, *args, **kwargs):
            # 获取数据
            roles = self.get_queryset()     # models.Role.objects.all()
            # [1,1000, ]  [1,10]
            pager_roles = self.paginate_queryset(roles)
            # 序列化 实例化
            ser = self.get_serializer(instance=pager_roles, many=True)
            return Response(ser.data)
    
    d.GenericViewSet

    class GenericViewSet(ViewSetMixin, generics.GenericAPIView): 没背景...家底殷实

    路由:

    ​ url(r'^(?P[v1|v2]+)/view1/$', views.View1View.as_view({'get': 'list'})),

    视图:

    from rest_framework.viewsets import GenericViewSet
    class View1View(GenericViewSet):
            queryset = models.Role.objects.all()
            serializer_class = PagerSerialiser
            pagination_class = PageNumberPagination
    
            def list(self, request, *args, **kwargs):  # 重写了as_view() 那个父类
                # 获取数据
                roles = self.get_queryset()  # models.Role.objects.all()
                # [1,1000, ]  [1,10]
                pager_roles = self.paginate_queryset(roles)
                # 序列化 实例化
                ser = self.get_serializer(instance=pager_roles, many=True)
                return Response(ser.data)
    
    e.路由系统:两个视图
    url(r'^(?P<version>[v1|v2]+)/view1/$', views.View1View.as_view({'get': 'list', 'post': 'create'})),
    url(r'^(?P<version>[v1|v2]+)/view1/(?P<pk>d+)/$', views.View1View.as_view({'get': 'retrieve', 'del
    
    views:(第一种写法)
    from rest_framework.viewsets import GenericViewSet, ModelViewSet
    from rest_framework.mixins import ListModelMixin
    class View1View(ListModelMixin, GenericViewSet, CreateModelMixin):
        queryset = models.Role.objects.all()
        serializer_class = PagerSerialiser
        pagination_class = PageNumberPagination
    

    路由:

    url(r'^(?P[v1|v2]+)/view1/$', views.View1View.as_view({'get': 'list', 'post': 'create'})),

    请求:

    http://127.0.0.1:8000/app01/v1/view1/

    显示:

    1568257584377

    1568257701357

    views:(第二种写法)
    class View1View(ModelViewSet):
        queryset = models.Role.objects.all()
        serializer_class = PagerSerialiser
        pagination_class = PageNumberPagination
    

    ModelViewSet

    继承的类

    class ModelViewSet(mixins.CreateModelMixin,			# post 更新
                       mixins.RetrieveModelMixin,		# get 执行单条数据
                       mixins.UpdateModelMixin,			# update patch 局部更新和全局
                       mixins.DestroyModelMixin,		# delete 删除 destroy
                       mixins.ListModelMixin,			# 分页吗?
                       GenericViewSet):					# 继承了两个类 就是ViewSetMixin, generics.GenericAPIView 
    

    路由:

    url(r'^(?P<version>[v1|v2]+)/view1/(?P<pk>d+)/$', views.View1View.as_view({'get': 'retrieve', 'delete': 'destroy', 'put': 'update', 'patch': 'partial_update'})),
                            # get执行单条数据了 有id    update partical_update 全部更新和局部更新
    

    请求: (因为是单条,传id)

    http://127.0.0.1:8000/app01/v1/view1/1/

    显示:

    1568257443660

    继承越多,写的越少, model继承了6个类, 增删改查更新Gener(也继承了两个)

    总结:

    简单的 用ModelViewSet

    非常复杂的用 APIVIew 和GenericViewSet

    不过用 GEn的 得在函数里区分,而不用的话,在model里的url中自己就有区分走不同的路由

    url(r'^(?P<version>[v1|v2]+)/view1/$', views.View1View.as_view({'get': 'list', 'post': 'create'})),
    url(r'^(?P<version>[v1|v2]+)/view1/(?P<pk>d+)/$', views.View1View.as_view({'get': 'retrieve', 'delete': 'destroy', 'put': 'update', 'patch': 'partial_update'})),
    

    类似于fbv和cbv if 判断 和 走 dispatch?

    没有单条的APIView更简洁

    a.增删改查 ModelViewSet

    b.增删 CreateModelMixin , DestroyModelMixin, GenericViewSet

    c.复杂逻辑

    GenericViewSet 和 APIVIew

    权限: (单个调用的流程)

    GenericViewSet.get_object

    ​ check_object_permissions

    ​ has_object_permission

    3.路由

    a.

    url(r'^(?P[v1|v2]+)/page1/$', views.Pager1View.as_view(), name='page1'),

    b.

    url(r'^(?P[v1|v2]+)/view1/$', views.View1View.as_view({'get': 'list', 'post': 'create'})),

    c.

    # <http://127.0.0.1:8000/app01/v1/view1/2/?format=json>
    url(r'^(?P<version>[v1|v2]+)/view1/$', views.View1View.as_view({'get': 'list', 'post': 'create'})),
    # http://127.0.0.1:8000/app01/v1/view1.json
    url(r'^(?P<version>[v1|v2]+)/view1.(?P<format>w+)$', views.View1View.as_view({'get': 'list', 'post': 'create'})),
    url(r'^(?P<version>[v1|v2]+)/view1/(?P<pk>d+)/$', views.View1View.as_view({'get': 'retrieve', 'delete': 'destroy', 'put': 'update', 'patch': 'partial_update'})),
    # http://127.0.0.1:8000/app01/v1/view1/2.json
    url(r'^(?P<version>[v1|v2]+)/view1/(?P<pk>d+).(?P<format>w+)$', views.View1View.as_view({'g
    

    混合这用

    路由:

    url(r'^(?P<version>[v1|v2]+)/view1.(?P<format>w+)$', views.View1View.as_view({'get': 'list', 'post': 'create'})),    # 转义
    

    请求:

    http://127.0.0.1:8000/app01/v1/view1.json

    响应:

    {"count":8,"next":"http://127.0.0.1:8000/app01/v1/view1.json?page=2","previous":null,"results":[{"id":2,"title":"善良"},{"id":3,"title":"活泼"}]}
    

    urls配置

    from django.conf.urls import url, include
    
    # 自动生成路由 (4个,前缀是xxxx,或者rt)
    from rest_framework import routers
    router = routers.DefaultRouter()
    router.register(r'xxxx', views.View1View)
    router.register(r'rt', views.View1View)
    #url(r'^', include(router.urls)),
    # 把版本带上
    url(r'^(?P<version>[v1|v2]+)/', include(router.urls)),
    
    

    自动生成路由

    1. ^app01/ ^(?P<version>[v1|v2]+)/ ^xxxx/$ [name='role-list']
      ^app01/ ^(?P<version>[v1|v2]+)/ ^xxxx.(?P<format>[a-z0-9]+)/?$ [name='role-list']
      ^app01/ ^(?P<version>[v1|v2]+)/ ^xxxx/(?P<pk>[^/.]+)/$ [name='role-detail']
      ^app01/ ^(?P<version>[v1|v2]+)/ ^xxxx/(?P<pk>[^/.]+).(?P<format>[a-z0-9]+)/?$ [name='role-detail']
      ^app01/ ^(?P<version>[v1|v2]+)/ ^rt/$ [name='role-list']
      ^app01/ ^(?P<version>[v1|v2]+)/ ^rt.(?P<format>[a-z0-9]+)/?$ [name='role-list']
      ^app01/ ^(?P<version>[v1|v2]+)/ ^rt/(?P<pk>[^/.]+)/$ [name='role-detail']
      ^app01/ ^(?P<version>[v1|v2]+)/ ^rt/(?P<pk>[^/.]+).(?P<format>[a-z0-9]+)/?$ [name='role-detail']
      

      增删改查(时可以用)

    4.渲染

    请求:

    http://127.0.0.1:8000/app01/v1/view1/2/?format=json

    响应:

    {"id":2,"title":"善良"}

    这是渲染,以json形式返回

    http://127.0.0.1:8000/app01/v1/view1/2/

    1568258971707

    这是路由, 返回页面

    http://127.0.0.1:8000/app01/v1/test/?format=json

    renderer_classes = [JSONRenderer,] # 渲染

    1568260635588

    renderer_classes = [BrowsableAPIRenderer,] # 渲染

    1568260578238

    renderer_classes = [AdminRenderer] # 渲染

    http://127.0.0.1:8000/app01/v1/test/?format=admin

    1568260535716

    局部处理

    # from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer, AdminRenderer, HTMLFormRenderer
    #  HTMLFormRenderer  : 显示表单,form
    class TestsView(APIView):
        # renderer_classes = [JSONRenderer, BrowsableAPIRenderer, AdminRenderer]  # 渲染
        # renderer_classes = [JSONRenderer]  # 够了
        # renderer_classes = [JSONRenderer, BrowsableAPIRenderer]  # 好看
    
    

    全局处理

    配置文件:

    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
     'rest_framework.renderers.BrowsableAPIRenderer'
    ]
    

    今日作业 :

    1. 序列化

    2. 视图继承流程

    3. 写代码

      a. vue

      ​ 登录页面

      ​ 输入用户名和密码, 发送ajax请求

      ​ 用户列表页面,将用户数据显示在页面中

      b. django rest framework

      ​ -/auth/

      ​ 返回token

      ​ -/student/

      ​ 返回学生列表

      ​ -/student/d+/

      ​ 返回学生详细信息

      c.节流:

      ​ 控制

      ​ -匿名用户 2分钟10次

      ​ -正常用户 2分钟10次

      ps:

      ​ CORS

  • 相关阅读:
    多态
    封装,继承,多态
    基本类型和引用类型的区别
    第七天 面向对象
    什么是Java线程池
    游戏内核架构
    放松
    静不下来心写代码
    速度和正确率
    理顺思路
  • 原文地址:https://www.cnblogs.com/Doner/p/11509397.html
Copyright © 2011-2022 走看看