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

posted @ 2019-09-11 23:03  learnacode  阅读(206)  评论(0编辑  收藏  举报