• 关于djangorestframework


    djangorestframework技术文档 restfrmework规范

    开发模式

    普通开发为前端和后端代码放在一起写
    前后端分离为前后端交互统统为ajax进行交互
    

    前后端分离

    优点:分工明细,节省开发周期。代码维护性强!
    

    后端开发

    为前端提供URL(API开发)

    django FBV和CBV

    FBV function base view CBV class base view

    FBV

    def student(request):
    #代码片段
    return HttpResponse('返回值')
    

    CBV

    views.py
    class StudentView(object):
        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('返回值')
    
    urls.py
    from django.conf.urls import url
    
    urlpatterns = [
        url(r'student/',views.StudentView.as_view()),
    ]
    

    回顾

    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 是对象列表
    

    面向对象

    -封装
    封装体现在两大方面,第一方面是类可以对同一类方法进行封装,另一方面是将数据封装到对象中。
    class File:
        #文件的增删改查方法
    class DB:
        #数据库的增删改查方法
           def get:
           def post:
           def update:
           def delete:
       class DB:
           def get:
           def post:
           def update:
           def delete:
    ### 将数据封装到对象中
       class File:
           def __init__(self,a1,a2):
               self.a1 = a1
               self.xxx = a2
           def get:...
           def post: ...
           def update: ...
           def add: ...
       obj1 = File(123,456)
       obj2 = File(456,789)
    

    封装示例.py

    class Request(object):
        def __init__(self,obj):
            self.obj = obj
        @property
        def user(self):
            return self.obj.aythticate()
    class Auth(object):
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def authticate(self):
            return True
    class APIView(object):
        def dispatch(self):
            self.f2()
        def f2(self):
            a = Auth('alex',18)
            req = Request(a)
            print(req.user)
    obj = APIView()
    obj.dispatch()
    

    把封装示例搞明白

    http_method_names = ['get','post','put','delete','patch','head', 'options', 'trace'']

    CBV:基于反射实现根据请求方式不同,执行不同的方法。

    原理:
    a.路由
        url 对应 自定义的view函数   对应 dispatch方法(根据反射执行其他方法:GET/POST/PUT/DELETE.....)
    

    继承(多个类共用的功能,为了避免重复编写,可以使用继承来实现。)

    from django.views import View
    
    class MyBaseView(object):
        def dispatch(self,request,*args,**kwargs):
        print('berfore')
        ret = super(MyBaseView,self).dispatch(request,*args,**kwargs)
        print('after')
        return ret
    
    class StudentView(MyBaseView,View):
        def get(self,request,*args,**kwargs):
            print('get方法')
            return HttpResponse('GET')
        def post(self,request,*args,**kwargs):
            print('POST方法')
            return HttpResponse('post')
        def put(self,request,*args,**kwargs):
            print('put方法')
            return HttpResponse('put')
        def delete(self,request,*args,**kwargs):
            print('delete方法')
            return HttpResponse('delete')
    
    Django中间件
    process_request
    process_response
    process_view
    process_exception
    process_render_template
    

    Django的中间件就是上面这些,没有其他的了

    小知识:

    请求进来先执行中间件所有的process_request,通过process_request后进行路由匹配,路由匹配之后在执行process_view,process_view执行完执行视图函数,视图函数如果没有出错执行完毕执行process_response,如果报错执行 process_exception ,如果视图函数返回的对象中有render方法,那就process_render_template也会被执行。

    使用中间件做过什么?
    权限
    用户登录验证
    csrf_token
    
    django的csrf是如何实现的?

    csrf中间件写在process_view里面_ process_view方法 检查视图函去请求体或cookie中获取token数是否被@csrf_exempt(免除csrf认证) 去请求体或cookie中获取token

    如何让函数免除csrf_token验证?

        from django.views.decorators.csrf import csrf_exempt
        @csrf_exempt
        def a():
            pass
    

    如何让函数需要csrf_token认证?

    settings.py中的csrf中间件认证被注释
    视图函数需要csrf_token认证
    
    from django.views.decorators.csrf import csrf_protect
    
    @csrf_protect
    def user():
        pass
    

    CBV特殊的东西! 如果想给cbv加上csrf_token csrf时需要使用 -@method_decorator(csrf_exempt) -在dispatch方法上加上(单独的方法加上无效)

    方法示例一:

    views.py
    
    from django.utils.decorators import method_decorator
    from django.views.decorators.csrf import csrf_exempt
    
    class Student(View):
        @method_decorator(csrf_exempt)
        def dispatch(self,request,*args,**kwargs):
            return super(StudentView,self).dispatch(self,*args,**kwargs)
       
        def get(self,request,*args,**kwargs):
            pass
       
        def post(self,request,*args,**kwargs):
            pass
    

    方法示例二:

    views.py
    
    from django.utils.decorators import method_decorator
    from django.views.decorators.csrf import csrf_exempt
    
    @method_decorator(csrf_exempt,name='dispatch')
    class Student(View):
        def dispatch(self,request,*args,**kwargs):
            return super(StudentView,self).dispatch(self,*args,**kwargs)
       
        def get(self,request,*args,**kwargs):
            pass
       
        def post(self,request,*args,**kwargs):
            pass
    
    
    总结:
    CBV 本质
        基于用户请求的方法和反射实现的
    CBV 流程
        请求 ----  路由 ---- view ---- dispatch(反射)
    取消csrf认证(装饰器要加到dispatch方法上)
    ,且method_decorator装饰)
    
    扩展
    -csrf
        -   基于中间件实现(process_view方法)
        -   基于装饰器给单独函数进行设置(认证或无需认证)
    
    
    restful 规范(建议)
    根据method不同做不同的操作
    示例(FBV):
    
    urlpatterns = [
    url(
    'order/',views.order
    )
    ]
    def order(request):
        if request.method =='GET':
            pass
        if request.method =='POST':
            pass
        if request.method =='PUT':
            pass
        if request.method =='DELETE':
            pass
    
        示例(CBV):
    
    urlpatterns = [
    url(
    'order/',views.OrderView.as_view()
    )
    ]
    
    class OrderView(View):
        def get(self,request,*args,**kwargs):
            pass
        def post(self,request,*args,**kwargs):
            pass
        def put(self,request,*args,**kwargs):
            pass
        def delete(self,request,*args,**kwargs):
            pass
    

    restful规范(10个规范) API与用户的通信协议,总是使用HTTPS协议. 域名:https://api.example.com #尽量将API于.

    子域名方式
    www.luffycity.com 
    api.luffycity.com
    
    URL方式
    www.luffycity.com
    www.luffycity.com/api/
    

    使用子域名的时候容易出现跨域 域名不同或者端口不同都会出现跨域

    使用URL的方式就不会出现跨域问题

    版本

    url :https://api.example.com/v1/
    
    请求头  
    
    跨域时,引发发送多次请求
    
    

    路径:视网络上任何东西都是资源,均使用名词表示(可复数)

    https://api/example.com/v1/zooms/
    
    

    method GET 从服务器取出资源(一项或多项)

    POST 在服务器新建一个资源
    
    PUT 在服务器更新紫云(客户端提供改变后的完整资源)
    
    PATCH 在服务器更新资源(客户端提供改变的属性)
    
    DELETE 从服务器删除资源
    
    

    过滤 通过url上传参数的形式传递搜索条件 http://api/example/v1/zooms/?limit=10 指定返回记录的数量

    状态码 常用状态码列表 200 成功 201 用户新建或修改数据成功 202 Accepted 表示一个请求已经进入后台排队(异步任务) 204 用户删除数据成功

    301 永久重定向
    302 临时重定向
    400 用户发出分请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的
    401 表示用户没有权限(令牌,用户名,密码错误)
    403 Forbiden 表示用户得到授权 ,但是访问被禁止的
    404 用户发出的请求针对是不存在的记录,服务器没有及逆行操作,该操作是幂等的
    406 用户请求的格式不可得,(比如用户请求json格式,但是只有xml格式)
    410 Gone 用户请求的资源被永久删除,且不会再得到
    422 当创建一个对象时,发生一个验证错误
    
    500 服务器错误
    
    

    状态码(status code)和code结合使用。

    ret = {
        "code":1000,
        "msg":"xxx"
    }
    
    

    错误处理

    {
        "error":"xxx",    
    }
    
    

    Hypermedia API result API 最好做到Hypermedia 即返回结果中提供链接,联向其他API方法,使得用户不查询 就能知道下一步怎么做

    {
    "link":{
        "id":1,
        "name":"苹果",
        "url":"https://api/example/order/1"
    }
    }
    
    

    谈谈你对restful api 规范的认识 伪装成老手讲故事:

    其实本质上就是一种规范,是可以让我们根据规范更好的对API进行处理,更容易让前端记住URL 节约的URL的数量
    
    

    django rest framework 框架

    安装
    pip install djangorestframework
    
    

    继承

    views.py
     
     from rest_framework.views import APIView
     
     class DogView(APIView):
        def get(self,request,*args,**kwargs):
            pass
        def post(self,request,*args,**kwargs):
            pass
        def put(self,request,*args,**kwargs):
            pass
    
    

    rest framework CBV 执行APIView里的dispatch方法

    认证 仅适用认证:

    views.py
        class DogView(APIView):
            authentication_class = [MyAuthentication,]
    
    

    csrf_token实现原理 用户发送get请求 后端生成TOKEN返回给用户,用户下次请求的时候必须携带后端返回的TOKEN

    为了验证token,restframework已经帮我们做好了

    class Authtication(object):
        token = request.__request.GET.get('token')
        token_obj = models.UserToken.objects.filter(token=token).first
        if not token_obj:
            raise exceptions.AuthenticationFailed('用户认证失败')
        return (token_obj.user,token_obj) 
        
    class OrderView(APIView):
        authentication_classes = [Authtication,]
        def get(self,request,*args,**kwargs):
    
    

    restframework支持认证全局配置

    认证流程原理
    认证可以在项目开发的settings.py下设置
    
        REST_FRAMEWORK = {
        "DEFAULT_AUTHENTICATION_CLASSES":[],
        "UNAUTHENTICATED_USER":[],
        "UNAUTHENTICATED_TOKEN":[],
    }
    
    

    如果需要使用自己写的认证类,就在对应的[]增加自己写的类的路径,把路径放在字符串里

    在自己写认证类的时候,自己的认证类必须继承 restframework 的BaseAuthentication, 因为 restframework里的BaseAuthentication里有个函数写的是默认报错!

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

    BasicAuthentication认证流程 前端把用户密码经过base64加密之后以HTTP_AUTHORIZATION为键,加密后的用户名和密码为值,传给后端,后端用request.META.get('HTTP_AUTHORIZATION', b'')拿到键值对,并把数据交给BasicAuthentication.authenticate去处理和解密得到用户名密码 用户名密码是以:进行切片,索引0是用户名 索引1是密码 并进行一系列

    restframework 提供了内置的认证类,丰富了认证方法 我们只要写认证类必须继承restframework的 baseAuthentication认证类 并在自己的类里重写authenticate方法

    梳理:

    1.使用
        创建类:继承BaseAuthentication 实现 authenticate方法
        返回值:
            None:我不管了,下一个认证来执行
             raise exceptions.AuthenticationFaild('用户认证失败')
        局部使用
            from rest_framework.authentication import BaseAuthentication,BasicAuthentication
            
            class UserInfoView(APIView):
                authentication_classes = [BasicAuthentication,]
                def get(self,request,*args,**kwargs):
                    pass
        全局使用
            
             REST_FRAMEWORK = {
        "DEFAULT_AUTHENTICATION_CLASSES":[],
        "UNAUTHENTICATED_USER":[],
        "UNAUTHENTICATED_TOKEN":[],
    }
    

    认证组件源码流程:

        -dispatch
            -封装 request
                -获取定义的认证类(全局/局部),通过列表生成式创建对象
            -initial
             perform_authentication
              request.user(内部循环.....)
              
    
    

    权限

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

      基本使用:
      				
      	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)
      
      源码流程:
      	- 请求进来 进入到dispatch
      	    -   封装request
      	        -   initial
      	            -认证
      	                -权限
      	                    -把类读过来,列表生成式生成对象,循环每一个对象,执行他的has_permission方法
      	
      梳理:
      	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']
      			}
      
      

    restframework节流

    请求数据进行校验
        QuerySet不能用HttpResponse返回给前端
        QuerySet只能进行序列化处理后返回给前端
    
    
    内容回顾
    谈谈面向对象?
    面向对象的三大特性!
        封装
            封装主要体现在类封装到对象中,把字段封装到对象个中!
        封装的特性在代码中哪里使用过?
        自定义分页的时候,把当前页的数据通过封装的方法
        start_config封装
        标准封装:
            django restframework 源码中体现的就是对request的封装
        标准继承:
            多继承, 经典类 和新式类
            
        将公共的功能放到基类中,让我们继承的时候可使用的方法多样化
        
        多态:
        鸭子模型: 只要听到鸭子呱呱叫,我就认为是鸭子,鹦鹉呱呱叫 我也认为是鸭子!
        
        多态体现
        class a:
            def send():
                pass
        class b:
            def send():
                pass
        class func(arg):
            arg.send()
        obj = a:
        func(obj)
    
    

    Django的生命周期: 一个请求首先经过wsgi ref模块 它是python的内置模块 wsgi 跟django没有任何关系! 只是django利用wsgi做了一个socket wsgi是干嘛的? wsgi与django应用之间的约束规范的一种协议 wsgiref是干嘛的? wsgiref是实现了wsgi协议的一个模块,模块本质:一个socket服务端 uwsgi在公司将项目部署的时候使用uwsgi

    werkzug 实现了wsgi协议的一个模块,一个socket服务端
    tornado 是实现wsfi协议到一个模块
    web server 有两个参数 environ start_response响应参数
    穿过所有的中间件后进行路由匹配
    视图函数通过ORM拿取数据模板拿模板进行渲染 数据通过json返回给模板展现出来
    
    视图里进行dispatch
    完整的说法:
    前端请求进来,通过 wsgi后,然后穿过所有的中间件进行路由匹配的时候先执行在函数里嵌套的as.view(),相当于执行了as.views里面的view内置函数!view函数里执行dispatch
    
    为什么执行dispatch?
    因为路由里的as_view帮我们做的
    先执行请求的封装,认证 权限 节流 通过反射找到函数进行执行
    
    

    中间件&装饰器 中间件用于统一做所有请求批量做操作方法要中间件来做

    你用中间件做过什么?
    认证(rbac)
    权限(基于权限的用户控制)
    csrf_token
        csrf_token原理
            第一次来的时候服务端给随机字符串,再来的时候把随机字符串带过来,服务端进行验证
    session原理
        请求进来将相关的数据交给服务端,服务端拿到数据取数据库去查
    session里有 process_request和process_response方法
    session也是基于中间件设计的
    
    
    中间件的使用场景
    基于角色的权限控制
    
        用户认证
    
        csrf 说原理
        
        session 说原理
        
        黑名单
        
        日志记录
    
    

    rest 框架原理

    认证流程
        请求进来 -dispatch -封装request
        把所有的认证对象封装到了request 进入到perform_authentication 调用request.user
        在request.user里面又调用我我们自己写的authentication方法
    认证类里面有几个方法
        一共两个方法
            authenticate
            authenticate_header
    权限流程
        请求进来-走dispatch 封装request 直接去列表生成式执行权限的方法
    权限有几种方法
        has_permission
    
    节流流程
        匿名的时候根据IP/代理唯一标识进行节流进行节流
        通过类的获取表示get_ident的方法得到IP或者代理获取到
        使用用户使用用户名进行节流
    

    restframework 版本

    自定义版本
    URL中通过GET传参
     views.py
     class ParamVersion(object):
        def determine_version(self,request,*args,**kwargs):
            version = request.query_params.get('version')
            return version
    class UserView(APIView):
        versioning_class = ParamVersion
        def get(self,request,*args,**kwargs):
        pass
    
    使用restframework 版本写好的使用方法
    在自己的settings里
    

    在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('用户列表')
    
    

    restframework 解析器

    前戏: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
    
    

    restframework 序列化(重要)

    ​ 序列化有两大功能 :

    ​ 1.对请求数据的校验

    ​ 2.对QuerySet验证

    ​ 序列化demo

    ​ 创建serializers.py文件

    此demo只是入门级demo,一般开发的时候不是下面这种写法!

    下面这种写法只是给刚接触restframework的朋友提供思路

    下面的写法也可以实现项目中的需求

    models.py
    from django.db import models
    
    class RoleModels(models.Model):
        title = models.CharField(max_lentch=32,verbase_name='名称')
    	def __str__(self):
            return self.title
        class Meta:
            db_table = 'Role'
            verbose_name = verbose_name_plural = '角色'
    
    serializers.py
    from rest_framework.serializers import Serializer
    from .models import RoleModels
    
    class RoleSerializer(Serializer)
    	title = serializer.CharField()
    	class Meta:
            model = RoleModels
            fields = ('id', 'title')
    
    
    views.py
    from django.http import HttpResponse
    from .serializers import RoleSerializer
    from .models import RoleModels
    from rest_framework.views import APIView
    import json
    class RolesView(APIView):
        def get(self,request,*args,**kwargs):
            roles = RoleModels.objects.all()
            ser = RoleSerializer(instance=roles,many=True)
            ret = json.dumps(ser.data,ensure_asii=False)
            return HttpResponse(ret)
            
            
    
    

    代码里序列化中的many=True 意思是 roles = models.RoleModels.objects.all() 这段代码

    roles拿到的是多条数据 ,所以在序列化中

    要使用many=True 如果我们要取单条数据的写法是 role = models.RoleModels.objects.all().first()

    序列化中把many改为many=False

    因为Django的ORM取到的数据是QuerySet

    所以需要通过序列化才能把数据返回给前端,如果不进行序列化就把数据返回出去就会报错

    方式2
    models.py
    from django.db import models
    
    class UserInfoModels(models.Model):
        user_type_choices = (
        	(1,'普通用户'),
            (2,'VIP'),
            (3,'VVIP'),
        )
        user_type = models.IntegerField(choices=user_type_choices)
        username = models.CharField(max_length=32,unique=True)
        password = models.CharField(max_length=64)
       	Roles = models.ManyToManyField("Role")
        def __str__(self):
            return self.username
        class Meta:
            db_table = 'UserInfo'
            verbose_name = verbose_name_plural = '用户'
            
    serializers.py
    
    from rest_framework.serializers import Serializer
    from .models import UserInfoModels
    
    class UserInfoSerializer(Serializer)
    	username = serializer.CharField()
        password = serializer.CharField()
        class Meta:
            model = UserInfoModels
            fields = ('id', 'username','password')
            
    views.py
    
    from django.http import HttpResponse
    from .serializers import UserInfoSerializer
    from .models import UserInfoModels
    from rest_framework.views import APIView
    import json
    
    class UserInfoView(APIView):
        def get(self,request,*args,**kwargs):
            users = UserInfoModels.Objects.all()
            ser = UserInfoSerializer(instance=users,many=True)
            ret = json.dumps(ser.data,ensure_asii=False)
            return HttpResponse(ret)
            
    
    

    知识点

    如何将user_type 从数字 显示成中文,不要显示user_type的键,显示它的值

    我们要在序列化中声明字段

    models.py
    from django.db import models
    
    class UserInfoModels(models.Model):
        user_type_choices = (
        	(1,'普通用户'),
            (2,'VIP'),
            (3,'VVIP'),
        )
        user_type = models.IntegerField(choices=user_type_choices)
        username = models.CharField(max_length=32,unique=True)
        password = models.CharField(max_length=64)
       	Roles = models.ManyToManyField("Role")
        def __str__(self):
            return self.username
        class Meta:
            db_table = 'UserInfo'
            verbose_name = verbose_name_plural = '用户'
            
    serializers.py
    
    from rest_framework.serializers import Serializer
    from .models import UserInfoModels
    
    class UserInfoSerializer(Serializer)
    	xxxx = serializer.CharField(source="get_user_type_display")
    	username = serializer.CharField()
        password = serializer.CharField()
        class Meta:
            model = UserInfoModels
            fields = ('id', 'username','password','xxxx')
    
    
    

    无论我们给这个字段起个xxxx的名字还是其他的名字 只要这个source是对的,就可以把中文展示出来,这里的get_user_type_display 之后get_ 和_display是固定的,中间的字段是你models里的字段,我们的UserInfoModels是不是有user_type这个字段,所以要写成get_user_type_display

    如果你的models里的字段是oooo ,那就写get_oooo_display,如果是username 那就写get_username_display 希望看到这里你能明白

    这个source也适用于Models中的ForeignKey,但是不适用于ManyToManyField

    如果要必须要使用ManyToManyField,我们只能在序列化中创建字段xxx = serializers.SerializerMethodField ,xxx是你models里ManyToManyField的字段名(这里只是演示说字段名是xxx)然后还需要在序列化下方定义一个函数

    如果通过source取不到 用下面这个方法

    serializer.py
    
    #我们以角色表为例子
    from rest_framework.serializers import Serializer
    from .models import RoleModels
    
    class RoleSerializer(Serializer)
    	title = serializer.CharField()
        xxxx = serializerSerializerMethodField()
        def get_xxxx(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
    	class Meta:
            model = RoleModels
            fields = ('id', 'title')
    

    实际开发中我们会在序列化中引用ModelSerializer,很少使用Serializer

    models.py
    from django.db import models
    
    class RoleModels(models.Model):
        title = models.CharField(max_lentch=32,verbase_name='名称')
    	def __str__(self):
            return self.title
        class Meta:
            db_table = 'Role'
            verbose_name = verbose_name_plural = '角色'
    
    serializers.py
    from rest_framework.serializers import ModelSerializer
    from .models import RoleModels
    
    class RoleSerializer(ModelSerializer)
    
    	class Meta:
            model = RoleModels
            fields = ('__all__')
    
    
    views.py
    from django.http import HttpResponse
    from .serializers import RoleSerializer
    from .models import RoleModels
    from rest_framework.views import APIView
    import json
    class RolesView(APIView):
        def get(self,request,*args,**kwargs):
            roles = RoleModels.objects.all()
            ser = RoleSerializer(instance=roles,many=True)
            ret = json.dumps(ser.data,ensure_asii=False)
            return HttpResponse(ret)
            
    

    部分总结:
    1. 写类

    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
    
    

    自动序列化连表

    	class UserInfoSerializer(serializers.ModelSerializer):
    					class Meta:
    						model = models.UserInfo
                        	fields = ("__all__")
                          #  fields=['id','use**rname','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('提交数据')
    
    

    restframework 分页

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

    分页,看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)
    

    restframework 路由系统

    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'})),
    

    restframework视图

    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)
    
    
    
    
    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
    		
    

    restframework 渲染器

    在settings.py的INSTALLED_APPS 增加'rest_framework'
    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',
    			]
    		}
    
  • 相关阅读:
    Github markdown页面内跳转
    github gist 无法访问
    Install pyaudio on Ubuntu
    删除链表的倒数第N个节点
    电话号码的字母组合
    最长公共前缀
    盛最多水的容器
    字符串转化整数与回文数
    Z 字形变换
    LeetCode1-5题
  • 原文地址:https://www.cnblogs.com/pythonliuwei/p/12449410.html
Copyright © 2020-2023  润新知