b站4天课程笔记


s7day128

内容回顾:

1. 开发模式
    - 普通开发方式(前后端放在一起写)
    - 前后端分离

2. 后端开发
    为前端提供URL(API/接口的开发)
    注:永远返回HttpResponse

3. Django FBV、CBV
    FBV,function base view
        def users(request):
            user_list = ['alex','oldboy']
            return HttpResponse(json.dumps((user_list)))

    CBV,class base view 
        路由:
            url(r'^students/', views.StudentsView.as_view()),

        视图:
            from django.views import View

            class StudentsView(View):

                def get(self,request,*args,**kwargs):
                    return HttpResponse('GET')

                def post(self, request, *args, **kwargs):
                    return HttpResponse('POST')

                def put(self, request, *args, **kwargs):
                    return HttpResponse('PUT')

                def delete(self, request, *args, **kwargs):
                    return HttpResponse('DELETE')
4. 列表生成时

    class Foo:
        pass

    class Bar:
        pass

    v = []
    for i in [Foo,Bar]:
        obj = i()
        v.append(obj)


    v = [item() for item in [Foo,Bar]]

    v对象列表

5. 面向对象
    - 封装
        - 对同一类方法封装到类中
            class File:
                文件增删改查方法

            Class DB:
                数据库的方法

        - 将数据封装到对象中
            class File:
                def __init__(self,a1,a2):
                    self.a1 = a1 
                    self.xxx = a2
                def get:...
                def delete:...
                def update:...
                def add:...

            obj1 = File(123,666)
            obj2 = File(456,999)

        PS: 扩展 
            class Request(object):

                def __init__(self,obj):
                    self.obj = obj

                @property
                def user(self):
                    return self.obj.authticate()

            class Auth(object):
                def __init__(self,name,age):
                    self.name = name
                    self.age = age

                def authticate(self):
                    return self.name


            class APIView(object):

                def dispatch(self):
                    self.f2()

                def f2(self):
                    a = Auth('alex',18)
                    b = Auth('oldboy',18)
                    req = Request(b)
                    print(req.user)

            obj = APIView()
            obj.dispatch()

今日概要:

1. restful 规范(建议)

2. django rest framework框架

内容详细:

0. FBV、CBV
    CBV,基于反射实现根据请求方式不同,执行不同的方法。
    原理:
        url -> view方法 -> dispatch方法(反射执行其他:GET/POST/DELETE/PUT)

    流程:
        class StudentsView(View):
            def dispatch(self, request, *args, **kwargs):
                print('before')
                ret = super(StudentsView,self).dispatch(request, *args, **kwargs)
                print('after')
                return ret

            def get(self,request,*args,**kwargs):
                return HttpResponse('GET')

            def post(self, request, *args, **kwargs):
                return HttpResponse('POST')

            def put(self, request, *args, **kwargs):
                return HttpResponse('PUT')

            def delete(self, request, *args, **kwargs):
                return HttpResponse('DELETE')

    继承(多个类共用的功能,为了避免重复编写):
        from django.views import View


        class MyBaseView(object):
            def dispatch(self, request, *args, **kwargs):
                print('before')
                ret = super(MyBaseView,self).dispatch(request, *args, **kwargs)
                print('after')
                return ret

        class StudentsView(MyBaseView,View):

            def get(self,request,*args,**kwargs):
                print('get方法')
                return HttpResponse('GET')

            def post(self, request, *args, **kwargs):
                return HttpResponse('POST')

            def put(self, request, *args, **kwargs):
                return HttpResponse('PUT')

            def delete(self, request, *args, **kwargs):
                return HttpResponse('DELETE')

        class TeachersView(MyBaseView,View):

            def get(self,request,*args,**kwargs):
                return HttpResponse('GET')

            def post(self, request, *args, **kwargs):
                return HttpResponse('POST')

            def put(self, request, *args, **kwargs):
                return HttpResponse('PUT')

            def delete(self, request, *args, **kwargs):
                return HttpResponse('DELETE')

    面试题:
        1. django中间件
            - process_request
            - process_view
            - process_response
            - process_exception
            - process_render_template
        2. 使用中间件做过什么?
            - 权限
            - 用户登录验证
            - django的csrf是如何实现?
                process_view方法
                    - 检查视图是否被 @csrf_exempt (免除csrf认证)
                    - 去请求体或cookie中获取token
        3. 
            情况一:
                MIDDLEWARE = [
                    'django.middleware.security.SecurityMiddleware',
                    'django.contrib.sessions.middleware.SessionMiddleware',
                    'django.middleware.common.CommonMiddleware',
                    'django.middleware.csrf.CsrfViewMiddleware', # 全站使用csrf认证
                    'django.contrib.auth.middleware.AuthenticationMiddleware',
                    'django.contrib.messages.middleware.MessageMiddleware',
                    'django.middleware.clickjacking.XFrameOptionsMiddleware',
                ]


                from django.views.decorators.csrf import csrf_exempt
                @csrf_exempt # 该函数无需认证
                def users(request):
                    user_list = ['alex','oldboy']
                    return HttpResponse(json.dumps((user_list)))

            情况二:
                MIDDLEWARE = [
                    'django.middleware.security.SecurityMiddleware',
                    'django.contrib.sessions.middleware.SessionMiddleware',
                    'django.middleware.common.CommonMiddleware',
                    #'django.middleware.csrf.CsrfViewMiddleware', # 全站不使用csrf认证
                    'django.contrib.auth.middleware.AuthenticationMiddleware',
                    'django.contrib.messages.middleware.MessageMiddleware',
                    'django.middleware.clickjacking.XFrameOptionsMiddleware',
                ]


                from django.views.decorators.csrf import csrf_exempt
                @csrf_protect # 该函数需认证
                def users(request):
                    user_list = ['alex','oldboy']
                    return HttpResponse(json.dumps((user_list)))


    CBV小知识,csrf时需要使用
        - @method_decorator(csrf_exempt)
        - 在dispatch方法中(单独方法无效)

        方式一:
            from django.views.decorators.csrf import csrf_exempt,csrf_protect
            from django.utils.decorators import method_decorator
            class StudentsView(View):

                @method_decorator(csrf_exempt)
                def dispatch(self, request, *args, **kwargs):
                    return super(StudentsView,self).dispatch(request, *args, **kwargs)

                def get(self,request,*args,**kwargs):
                    print('get方法')
                    return HttpResponse('GET')

                def post(self, request, *args, **kwargs):
                    return HttpResponse('POST')

                def put(self, request, *args, **kwargs):
                    return HttpResponse('PUT')

                def delete(self, request, *args, **kwargs):
                    return HttpResponse('DELETE')
        方式二:
            from django.views.decorators.csrf import csrf_exempt,csrf_protect
            from django.utils.decorators import method_decorator

            @method_decorator(csrf_exempt,name='dispatch')
            class StudentsView(View):

                def get(self,request,*args,**kwargs):
                    print('get方法')
                    return HttpResponse('GET')

                def post(self, request, *args, **kwargs):
                    return HttpResponse('POST')

                def put(self, request, *args, **kwargs):
                    return HttpResponse('PUT')

                def delete(self, request, *args, **kwargs):
                    return HttpResponse('DELETE')

    总结:
        - 本质,基于反射来实现
        - 流程:路由,view,dispatch(反射)
        - 取消csrf认证(装饰器要加到dispatch方法上且method_decorator装饰)

        扩展:
            - csrf 
                - 基于中间件的process_view方法
                - 装饰器给单独函数进行设置(认证或无需认证)


1. restful 规范(建议)
    a. 接口开发

        urlpatterns = [
            # url(r'^admin/', admin.site.urls),
            url(r'^get_order/', views.get_order),
            url(r'^add_order/', views.add_order),
            url(r'^del_order/', views.del_order),
            url(r'^update_order/', views.update_order),
        ]


        def get_order(request):
            return HttpResponse('')


        def add_order(request):
            return HttpResponse('')


        def del_order(request):
            return HttpResponse('')


        def update_order(request):
            return HttpResponse('')

    b. restful 规范(建议)

        1. 根据method不同做不同的操作,示例:

            基于FBV:
                urlpatterns = [
                    url(r'^order/', views.order),
                ]

                def order(request):
                    if request.method == 'GET':
                        return HttpResponse('获取订单')
                    elif request.method == 'POST':
                        return HttpResponse('创建订单')
                    elif request.method == 'PUT':
                        return HttpResponse('更新订单')
                    elif request.method == 'DELETE':
                        return HttpResponse('删除订单')
            基于CBV:
                urlpatterns = [
                    url(r'^order/', views.OrderView.as_view()),
                ]

                class OrderView(View):
                    def get(self,request,*args,**kwargs):
                        return HttpResponse('获取订单')

                    def post(self,request,*args,**kwargs):
                        return HttpResponse('创建订单')

                    def put(self,request,*args,**kwargs):
                        return HttpResponse('更新订单')

                    def delete(self,request,*args,**kwargs):
                        return HttpResponse('删除订单')


    c. 谈谈自己对restful api 规范的认识

        10个规则


    注意:推荐使用CBV



2. django rest framework框架
    pip3 install djangorestframework

    a. 认证 
        - 仅使用:
                from django.views import View
                from rest_framework.views import APIView
                from rest_framework.authentication import BasicAuthentication
                from rest_framework import exceptions
                from rest_framework.request import Request

                class MyAuthentication(object):
                    def authenticate(self,request):
                        token = request._request.GET.get('token')
                        # 获取用户名和密码,去数据校验
                        if not token:
                            raise exceptions.AuthenticationFailed('用户认证失败')
                        return ("alex",None)

                    def authenticate_header(self,val):
                        pass

                class DogView(APIView):
                    authentication_classes = [MyAuthentication,]

                    def get(self,request,*args,**kwargs):
                        print(request)
                        print(request.user)
                        ret  = {
                            'code':1000,
                            'msg':'xxx'
                        }
                        return HttpResponse(json.dumps(ret),status=201)

                    def post(self,request,*args,**kwargs):
                        return HttpResponse('创建Dog')

                    def put(self,request,*args,**kwargs):
                        return HttpResponse('更新Dog')

                    def delete(self,request,*args,**kwargs):
                        return HttpResponse('删除Dog')

        - 源码流程:
            dispatch...

作业:

1. 中间件
2. csrf 
3. CBV 
4. 规范 
    - 10条规范
    - 认识 
5. djangorestframework
    - 如何验证(基于数据库实现用户认证)
    - 源码流程(面向对象回顾流程)

预习:
    版本
    权限
    控制访问频率

s7day129 内容回顾:

1. 中间件

2. csrf原理

3. rest 10规范

4. 面向对象

5. django请求声明周期

6. django请求声明周期(包含rest framework框架)
   PS: dispatch

今日内容:

1. 认证
2. 权限
3. 节流(访问频率控制)
4. 版本

今日内容:

1. 认证
    a. 问题1:有些API需要用户登录成功之后,才能访问;有些无需登录就能访问。
    b. 基本使用认证组件
        解决:
            a. 创建两张表
            b. 用户登录(返回token并保存到数据库)
    c. 认证流程原理
        - 见图示

    d. 再看一遍源码
        1. 局部视图使用&全局使用
        2. 匿名是request.user = None

    e. 内置认证类
        1. 认证类,必须继承:from rest_framework.authentication import BaseAuthentication
        2. 其他认证类:BasicAuthentication

    梳理:
        1. 使用 
            - 创建类:继承BaseAuthentication; 实现:authenticate方法
            - 返回值:
                - None,我不管了,下一认证来执行。
                - raise exceptions.AuthenticationFailed('用户认证失败') # from rest_framework import exceptions
                - (元素1,元素2)  # 元素1赋值给request.user; 元素2赋值给request.auth 

            - 局部使用
                from rest_framework.authentication import BaseAuthentication,BasicAuthentication
                class UserInfoView(APIView):
                    """
                    订单相关业务
                    """
                    authentication_classes = [BasicAuthentication,]
                    def get(self,request,*args,**kwargs):
                        print(request.user)
                        return HttpResponse('用户信息')
            - 全局使用:
                REST_FRAMEWORK = {
                    # 全局使用的认证类
                    "DEFAULT_AUTHENTICATION_CLASSES":['api.utils.auth.FirstAuthtication','api.utils.auth.Authtication', ],
                    # "UNAUTHENTICATED_USER":lambda :"匿名用户"
                    "UNAUTHENTICATED_USER":None, # 匿名,request.user = None
                    "UNAUTHENTICATED_TOKEN":None,# 匿名,request.auth = None
                }
        2. 源码流程
            - dispatch
                - 封装request
                    - 获取定义的认证类(全局/局部),通过列表生成时创建对象。
                - initial
                    - perform_authentication
                        request.user(内部循环....)


2. 权限 
    问题:不用视图不用权限可以访问

    基本使用:

        class MyPermission(object):

            def has_permission(self,request,view):
                if request.user.user_type != 3:
                    return False
                return True


            class OrderView(APIView):
                """
                订单相关业务(只有SVIP用户有权限)
                """
                permission_classes = [MyPermission,]

                def get(self,request,*args,**kwargs):
                    # request.user
                    # request.auth
                    self.dispatch
                    ret = {'code':1000,'msg':None,'data':None}
                    try:
                        ret['data'] = ORDER_DICT
                    except Exception as e:
                        pass
                    return JsonResponse(ret)

    源码流程:
        - ...

    梳理:
        1. 使用
            - 类,必须继承:BasePermission,必须实现:has_permission方法
                from rest_framework.permissions import BasePermission

                class SVIPPermission(BasePermission):
                    message = "必须是SVIP才能访问"
                    def has_permission(self,request,view):
                        if request.user.user_type != 3:
                            return False
                        return True
            - 返回值:  
                - True, 有权访问
                - False,无权访问
            - 局部 
                class UserInfoView(APIView):
                    """
                    订单相关业务(普通用户、VIP)
                    """
                    permission_classes = [MyPermission1, ]

                    def get(self,request,*args,**kwargs):
                        return HttpResponse('用户信息')

            - 全局 
                REST_FRAMEWORK = {
                    "DEFAULT_PERMISSION_CLASSES":['api.utils.permission.SVIPPermission']
                }

        2. 源码流程 


3. 访问频率控制(节流)
    问题:控制访问频率 
        import time
        VISIT_RECORD = {}

        class VisitThrottle(object):
            """60s内只能访问3次"""

            def __init__(self):
                self.history = None

            def allow_request(self,request,view):
                # 1. 获取用户IP
                remote_addr = request.META.get('REMOTE_ADDR')
                ctime = time.time()
                if remote_addr not in VISIT_RECORD:
                    VISIT_RECORD[remote_addr] = [ctime,]
                    return True
                history = VISIT_RECORD.get(remote_addr)
                self.history = history

                while history and history[-1] < ctime - 60:
                    history.pop()

                if len(history) < 3:
                    history.insert(0,ctime)
                    return True

                # return True    # 表示可以继续访问
                # return False # 表示访问频率太高,被限制

            def wait(self):
                """
                还需要等多少秒才能访问
                :return:
                """
                ctime = time.time()
                return 60 - (ctime - self.history[-1])

        class AuthView(APIView):
            """
            用于用户登录认证
            """
            authentication_classes = []
            permission_classes = []
            throttle_classes = [VisitThrottle,]

            def post(self,request,*args,**kwargs):


                ret = {'code':1000,'msg':None}
                try:
                    user = request._request.POST.get('username')
                    pwd = request._request.POST.get('password')
                    obj = models.UserInfo.objects.filter(username=user,password=pwd).first()
                    if not obj:
                        ret['code'] = 1001
                        ret['msg'] = "用户名或密码错误"
                    # 为登录用户创建token
                    token = md5(user)
                    # 存在就更新,不存在就创建
                    models.UserToken.objects.update_or_create(user=obj,defaults={'token':token})
                    ret['token'] = token
                except Exception as e:
                    ret['code'] = 1002
                    ret['msg'] = '请求异常'

                return JsonResponse(ret)

    源码流程: 
        ...

    内置控制频率类:
        from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
        class VisitThrottle(SimpleRateThrottle):
            scope = "Luffy"

            def get_cache_key(self, request, view):
                return self.get_ident(request)


        class UserThrottle(SimpleRateThrottle):
            scope = "LuffyUser"

            def get_cache_key(self, request, view):
                return request.user.username


        REST_FRAMEWORK = {
            # 全局使用的认证类
            "DEFAULT_AUTHENTICATION_CLASSES":['api.utils.auth.FirstAuthtication','api.utils.auth.Authtication', ],
            # "DEFAULT_AUTHENTICATION_CLASSES":['api.utils.auth.FirstAuthtication', ],
            # "UNAUTHENTICATED_USER":lambda :"匿名用户"
            "UNAUTHENTICATED_USER":None, # 匿名,request.user = None
            "UNAUTHENTICATED_TOKEN":None,# 匿名,request.auth = None
            "DEFAULT_PERMISSION_CLASSES":['api.utils.permission.SVIPPermission'],
            "DEFAULT_THROTTLE_CLASSES":["api.utils.throttle.UserThrottle"],
            "DEFAULT_THROTTLE_RATES":{
                "Luffy":'3/m',
                "LuffyUser":'10/m',
            }
        }


    梳理: 
        a. 基本使用 
            - 类, 继承:BaseThrottle,实现:allow_request、wait
            - 类, 继承:SimpleRateThrottle,实现:get_cache_key、scope = "Luffy"(配置文件中的key)

        b. 局部 
            class AuthView(APIView):
                """
                用于用户登录认证
                """
                authentication_classes = []
                permission_classes = []
                throttle_classes = [VisitThrottle,] # *******************

                def post(self,request,*args,**kwargs):

                    ret = {'code':1000,'msg':None}
                    try:
                        user = request._request.POST.get('username')
                        pwd = request._request.POST.get('password')
                        obj = models.UserInfo.objects.filter(username=user,password=pwd).first()
                        if not obj:
                            ret['code'] = 1001
                            ret['msg'] = "用户名或密码错误"
                        # 为登录用户创建token
                        token = md5(user)
                        # 存在就更新,不存在就创建
                        models.UserToken.objects.update_or_create(user=obj,defaults={'token':token})
                        ret['token'] = token
                    except Exception as e:
                        ret['code'] = 1002
                        ret['msg'] = '请求异常'

                    return JsonResponse(ret)

        c. 全局
            REST_FRAMEWORK = {
                # 全局使用的认证类
                "DEFAULT_AUTHENTICATION_CLASSES":['api.utils.auth.FirstAuthtication','api.utils.auth.Authtication', ],
                # "DEFAULT_AUTHENTICATION_CLASSES":['api.utils.auth.FirstAuthtication', ],
                # "UNAUTHENTICATED_USER":lambda :"匿名用户"
                "UNAUTHENTICATED_USER":None, # 匿名,request.user = None
                "UNAUTHENTICATED_TOKEN":None,# 匿名,request.auth = None
                "DEFAULT_PERMISSION_CLASSES":['api.utils.permission.SVIPPermission'],

                "DEFAULT_THROTTLE_CLASSES":["api.utils.throttle.UserThrottle"],
                "DEFAULT_THROTTLE_RATES":{
                    "Luffy":'3/m',
                    "LuffyUser":'10/m',
                }
            }

今日作业: 昨天:

1. 中间件
    2. csrf 
    3. CBV 
    4. 规范 
        - 10条规范
        - 认识 
    5. djangorestframework
        - 如何验证(基于数据库实现用户认证)
        - 源码流程(面向对象回顾流程)
今天上午:
    1. 中间件

    2. csrf原理

    3. rest 10规范

    4. 面向对象

    5. django请求声明周期

    6. django请求声明周期(包含rest framework框架)
       PS: dispatch

    7. rest framework 认证流程(封装Request.user)

    8. rest framework 权限流程

    9. rest framework 节流流程

代码:
    认证Demo,
    权限Demo(用户类型不同,权限不同)
    节流Demo(匿名,登录用)

    三组件组合

s7day130

内容回顾:

1. 谈谈面向对象?

2. Django声明周期
    a. wsgi
        wsgi,是协议。
        wsgiref,是实现了wsgi协议的一个模块。模块本质:一个socket服务端。(Django)
        werkzeug ,是实现了wsgi协议的一个模块。模块本质:一个socket服务端(Flask框架)
        tornado ,是实现了wsgi协议的一个模块。模块本质:一个socket服务端(Flask框架)
        uwsgi,是实现了wsgi协议的一个模块。模块本质:一个socket服务端。


3. Django生命周期(rest framework)


4. 中间件&装饰器
    - 适用于所有请求批量做操作
        场景:
            - 基于角色的权限控制
            - 用户认证
            - csrf,(说原理)
            - session(说原理)
            - 黑名单
            - 日志记录
5. rest 框架原理
    a. 认证流程
    b. 权限
    c. 节流

今日内容概要:

1. 版本     *
2. 解析器 *
3. 序列化 ****
    - 请求数据进行校验
    - QuerySet进行序列化
4. 分页   **
5. 路由   **
6. 视图   **
7. 渲染器 *

内容详细:

1. 版本
    a. URL中通过GET传参()
        自定义:
            http://127.0.0.1:8000/api/users/?version=v2

            class ParamVersion(object):
                def determine_version(self, request, *args, **kwargs):
                    version = request.query_params.get('version')
                    return version

            class UsersView(APIView):

                versioning_class = ParamVersion
                def get(self,request,*args,**kwargs):
                    #version = request._request.GET.get('version')
                    #print(version)
                    # version = request.query_params.get('version')
                    # print(version)

                    print(request.version)

                    return HttpResponse('用户列表')


    b. 在URL中传参(推荐使用)

        urlpatterns = [
            # url(r'^admin/', admin.site.urls),
            url(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view()),
        ]


        REST_FRAMEWORK = {
            "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
            "DEFAULT_VERSION":'v1',
            "ALLOWED_VERSIONS":['v1','v2'],
            "VERSION_PARAM":'version',
        }

        class UsersView(APIView):

            def get(self,request,*args,**kwargs):
                print(request.version)
                return HttpResponse('用户列表')

    总结:
        使用:
            配置文件:
                REST_FRAMEWORK = {
                    "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
                    "DEFAULT_VERSION":'v1',
                    "ALLOWED_VERSIONS":['v1','v2'],
                    "VERSION_PARAM":'version',
                }
            路由系统:

                urlpatterns = [
                    # url(r'^admin/', admin.site.urls),
                    url(r'^api/', include('api.urls')),
                ]

                urlpatterns = [
                    # url(r'^admin/', admin.site.urls),
                    url(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view(),name='uuu'),
                ]


            视图:

                class UsersView(APIView):

                def get(self,request,*args,**kwargs):

                    # 1. 获取版本
                    print(request.version)

                    # 2. 获取处理版本的对象
                    print(request.versioning_scheme)

                    # 3. 反向生成URL(rest framework)
                    u1 = request.versioning_scheme.reverse(viewname='uuu',request=request)
                    print(u1)

                    # 4. 反向生成URL
                    u2 = reverse(viewname='uuu',kwargs={'version':2})
                    print(u2)

                    return HttpResponse('用户列表')

2. 解析器
    前戏:django:request.POST/ request.body
        1. 请求头要求:
            Content-Type: application/x-www-form-urlencoded
            PS: 如果请求头中的 Content-Type: application/x-www-form-urlencoded,request.POST中才有值(去request.body中解析数据)。
        2. 数据格式要求:
              name=alex&age=18&gender=男

        如:
            a. form表单提交
                <form method...>
                    input...

                </form>

            b. ajax提交
                $.ajax({
                    url:...
                    type:POST,
                    data:{name:alex,age=18} # 内部转化 name=alex&age=18&gender=男
                })

                情况一:
                    $.ajax({
                        url:...
                        type:POST,
                        headers:{'Content-Type':"application/json"}
                        data:{name:alex,age=18} # 内部转化 name=alex&age=18&gender=男
                    })
                    # body有值;POST无
                情况二:
                    $.ajax({
                        url:...
                        type:POST,
                        headers:{'Content-Type':"application/json"}
                        data:JSON.stringfy({name:alex,age=18}) # {name:alex,age:18...}
                    })
                    # body有值;POST无
                    # json.loads(request.body)

    rest_framework 解析器,对请求体数据进行解析

    总结:
        使用: 
            配置:
                REST_FRAMEWORK = {
                    "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
                    "DEFAULT_VERSION":'v1',
                    "ALLOWED_VERSIONS":['v1','v2'],
                    "VERSION_PARAM":'version',

                    "DEFAULT_PARSER_CLASSES":['rest_framework.parsers.JSONParser','rest_framework.parsers.FormParser']
                }

            使用:
                class ParserView(APIView):
                    # parser_classes = [JSONParser,FormParser,]
                    """
                    JSONParser:表示只能解析content-type:application/json头
                    JSONParser:表示只能解析content-type:application/x-www-form-urlencoded头
                    """

                    def post(self,request,*args,**kwargs):
                        """
                        允许用户发送JSON格式数据
                            a. content-type: application/json
                            b. {'name':'alex',age:18}
                        :param request:
                        :param args:
                        :param kwargs:
                        :return:
                        """
                        """
                        1. 获取用户请求
                        2. 获取用户请求体
                        3. 根据用户请求头 和 parser_classes = [JSONParser,FormParser,] 中支持的请求头进行比较
                        4. JSONParser对象去请求体
                        5. request.data
                        """
                        print(request.data)


                        return HttpResponse('ParserView')


        源码流程 & 本质:
            a. 本质 
                请求头 :...
                状态码: ...
                请求方法:...
            b. 源码流程 
                - dispatch: request封装 
                - request.data 



3. 序列化 

    序列化:
        部分总结:
            1. 写类
                class RolesSerializer(serializers.Serializer):
                    id = serializers.IntegerField()
                    title = serializers.CharField()

                class UserInfoSerializer(serializers.ModelSerializer):
                    class Meta:
                        model = models.UserInfo
                        # fields = "__all__"
                        fields = ['id','username','password',]

            2. 字段 
                a. title = serializers.CharField(source="xxx.xxx.xx.xx")
                b. title = serializers.SerializerMethodField()
                   class UserInfoSerializer(serializers.ModelSerializer):
                        rls = serializers.SerializerMethodField()  # 自定义显示

                        class Meta:
                            model = models.UserInfo
                            fields = ['id','username','password','rls',]

                        # 自定义方法
                        def get_rls(self, row):
                            role_obj_list = row.roles.all()

                            ret = []
                            for item in role_obj_list:
                                ret.append({'id':item.id,'title':item.title})
                            return ret
                c. 自定义类

            3. 自动序列化连表
                class UserInfoSerializer(serializers.ModelSerializer):
                class Meta:
                    model = models.UserInfo
                    # fields = "__all__"
                    fields = ['id','username','password','group','roles']
                    depth = 1 # 0 ~ 10

            4. 生成链接
                class UserInfoSerializer(serializers.ModelSerializer):
                    group = serializers.HyperlinkedIdentityField(view_name='gp',lookup_field='group_id',lookup_url_kwarg='xxx')
                    class Meta:
                        model = models.UserInfo
                        # fields = "__all__"
                        fields = ['id','username','password','group','roles']
                        depth = 0 # 0 ~ 10

                class UserInfoView(APIView):
                    def get(self,request,*args,**kwargs):

                        users = models.UserInfo.objects.all()

                        ser = UserInfoSerializer(instance=users,many=True,context={'request': request})
                        ret = json.dumps(ser.data, ensure_ascii=False)
                        return HttpResponse(ret)

        源码:
            对象, Serializer类处理;
            QuerySet,ListSerializer类处理;
            # ser.data

    请求数据校验:

            class XXValidator(object):
                def __init__(self, base):
                    self.base = base

                def __call__(self, value):
                    if not value.startswith(self.base):
                        message = '标题必须以 %s 为开头。' % self.base
                        raise serializers.ValidationError(message)

                def set_context(self, serializer_field):
                    """
                    This hook is called by the serializer instance,
                    prior to the validation call being made.
                    """
                    # 执行验证之前调用,serializer_fields是当前字段对象
                    pass

            class UserGroupSerializer(serializers.Serializer):
                title = serializers.CharField(error_messages={'required':'标题不能为空'},validators=[XXValidator('老男人'),])


            class UserGroupView(APIView):

                def post(self,request,*args,**kwargs):

                    ser = UserGroupSerializer(data=request.data)
                    if ser.is_valid():
                        print(ser.validated_data['title'])
                    else:
                        print(ser.errors)

                    return HttpResponse('提交数据')


        问: 自定义验证规则时,需要钩子函数?请问钩子函数如何写?

今日作业:

1. 今日内容

2. 序列化自定义钩子函数

s7day131

内容回顾:

1. rest规范

2. rest framework
    - 要求:前4个组件
    - 序列化

今日内容概要:

0. 序列化源码

1. 分页
    a. 分页,看第n页,每页显示n条数据;
        from rest_framework.pagination import PageNumberPagination

        class MyPageNumberPagination(PageNumberPagination):

            page_size = 2
            page_size_query_param = 'size'
            max_page_size = 5
            page_query_param = 'page'

        class Pager1View(APIView):

            def get(self,request,*args,**kwargs):

                # 获取所有数据
                roles = models.Role.objects.all()

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

                # 在数据库中获取分页的数据
                pager_roles = pg.paginate_queryset(queryset=roles,request=request,view=self)

                # 对数据进行序列化
                ser = PagerSerialiser(instance=pager_roles, many=True)

                return Response(ser.data)
                # return pg.get_paginated_response(ser.data)


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

            from api.utils.serializsers.pager import PagerSerialiser
            from rest_framework.response import Response
            from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination


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


            class Pager1View(APIView):

                def get(self,request,*args,**kwargs):

                    # 获取所有数据
                    roles = models.Role.objects.all()

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

                    # 在数据库中获取分页的数据
                    pager_roles = pg.paginate_queryset(queryset=roles,request=request,view=self)

                    # 对数据进行序列化
                    ser = PagerSerialiser(instance=pager_roles, many=True)

                    return Response(ser.data)
                    # return pg.get_paginated_response(ser.data)



    c. 加密分页,上一页和下一页。

        from api.utils.serializsers.pager import PagerSerialiser
        from rest_framework.response import Response
        from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination

        class MyCursorPagination(CursorPagination):
            cursor_query_param = 'cursor'
            page_size = 2
            ordering = 'id'
            page_size_query_param = None
            max_page_size = None

        class Pager1View(APIView):

            def get(self,request,*args,**kwargs):

                # 获取所有数据
                roles = models.Role.objects.all()

                # 创建分页对象
                # pg = CursorPagination()
                pg = MyCursorPagination()

                # 在数据库中获取分页的数据
                pager_roles = pg.paginate_queryset(queryset=roles,request=request,view=self)

                # 对数据进行序列化
                ser = PagerSerialiser(instance=pager_roles, many=True)

                # return Response(ser.data)
                return pg.get_paginated_response(ser.data)
    总结:
        1. 数据量大的话,如何做分页?
            - 数据库性能相关?
2. 视图
    a. 过去 
        class Pager1View(View):
            pass

    b. 现在 
        class Pager1View(APIView): # View
            pass

    c. 无用

        from api.utils.serializsers.pager import PagerSerialiser
        from rest_framework.generics import GenericAPIView

        class View1View(GenericAPIView): # APIView
            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(ViewSetMixin, generics.GenericAPIView):

        路由:
            url(r'^(?P<version>[v1|v2]+)/v1/$', views.View1View.as_view({'get': 'list'})),

        视图:
            from api.utils.serializsers.pager import PagerSerialiser
            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):
                    # 获取数据
                    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]+)/v1/$', views.View1View.as_view({'get': 'list','post':'create'})),
            url(r'^(?P<version>[v1|v2]+)/v1/(?P<pk>\d+)/$', views.View1View.as_view({'get': 'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),

        视图:
            from api.utils.serializsers.pager import PagerSerialiser
            from rest_framework.viewsets import GenericViewSet,ModelViewSet
            from rest_framework.mixins import ListModelMixin,CreateModelMixin

            class View1View(ModelViewSet):
                queryset = models.Role.objects.all()
                serializer_class = PagerSerialiser
                pagination_class = PageNumberPagination

            PS: class View1View(CreateModelMixin,GenericViewSet):
    总结:
        a. 增删改查 ModelViewSet
        b. 增删     CreateModelMixin,DestroyModelMixin  GenericViewSet
        c. 复杂逻辑  GenericViewSet 或 APIView 

        PS: 还债: 
            GenericAPIView.get_object
                check_object_permissions
                    has_object_permission

3. 路由
    a. 
        url(r'^(?P<version>[v1|v2]+)/parser/$', views.ParserView.as_view()),

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

    c. 
        # http://127.0.0.1:8000/api/v1/v1/?format=json
        url(r'^(?P<version>[v1|v2]+)/v1/$', views.View1View.as_view({'get': 'list','post':'create'})),
        # http://127.0.0.1:8000/api/v1/v1.json
        url(r'^(?P<version>[v1|v2]+)/v1\.(?P<format>\w+)$', views.View1View.as_view({'get': 'list','post':'create'})),

        url(r'^(?P<version>[v1|v2]+)/v1/(?P<pk>\d+)/$', views.View1View.as_view({'get': 'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
        url(r'^(?P<version>[v1|v2]+)/v1/(?P<pk>\d+)\.(?P<format>\w+)$', views.View1View.as_view({'get': 'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
    d. 
        from api import views
        from rest_framework import routers


        router = routers.DefaultRouter()
        router.register(r'xxxxx', views.View1View)
        router.register(r'rt', views.View1View)

        urlpatterns = [
            url(r'^(?P<version>[v1|v2]+)/', include(router.urls)),
        ]

4. 渲染
    from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer

    class TestView(APIView):
        # renderer_classes = [JSONRenderer,BrowsableAPIRenderer]
        def get(self, request, *args, **kwargs):
            # 获取所有数据
            roles = models.Role.objects.all()

            # 创建分页对象
            # pg = CursorPagination()
            pg = MyCursorPagination()

            # 在数据库中获取分页的数据
            pager_roles = pg.paginate_queryset(queryset=roles, request=request, view=self)

            # 对数据进行序列化
            ser = PagerSerialiser(instance=pager_roles, many=True)

            return Response(ser.data)


    REST_FRAMEWORK = {
        "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
        "DEFAULT_VERSION":'v1',
        "ALLOWED_VERSIONS":['v1','v2'],
        "VERSION_PARAM":'version',
        "DEFAULT_PARSER_CLASSES":['rest_framework.parsers.JSONParser','rest_framework.parsers.FormParser'],
        "PAGE_SIZE":2,

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

5. django组件:contenttype

今日作业:

1. 序列化 
2. 视图继承流程
3. 写代码 
    a. vue
        - 看到登录页面
        - 数据用户名和密码,发送ajax请求

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

        - 学生详细信息

    b. django rest framework
        - /auth/
            返回token
        - /students/(认证)
            返回学生列表
        - /students/\d+/
            返回学生详细信息

    c. 节流:
        控制
            - 匿名用户  2分钟10次
            - 正常用户  2分钟20次

PS: 
    CORS