【DRF】认证组件/权限组件

三大认证源码分析 1)APIView的dispath(self, request, *args, **kwargs) 2)dispath方法内 self.initial(request, *args, **kwargs) 进入三大认证 # 认证组件:校验用户 - 游客、合法用户、非法用户 # 游客:代表校验通过,直接进入下一步校验(权限校验) # 合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验) # 非法用户:代表校验失败,抛出异常,返回403权限异常结果 self.perform_authentication(request) # 权限组件:校验用户权限 - 必须登录、所有用户、登录读写游客只读、自定义用户角色 # 认证通过:可以进入下一步校验(频率认证) # 认证失败:抛出异常,返回403权限异常结果 self.check_permissions(request) # 频率组件:限制视图接口被访问的频率次数 - 限制的条件(IP、id、唯一键)、频率周期时间(s、m、h)、频率的次数(3/s) # 没有达到限次:正常访问接口 # 达到限次:限制时间内不能访问,限制时间达到后,可以重新访问 self.check_throttles(request) 3) 认证组件 Request类的 方法属性 user 的get方法 => self._authenticate() 完成认证 认证的细则: # 做认证 def _authenticate(self): # 遍历拿到一个个认证器,进行认证 # self.authenticators配置的一堆认证类产生的认证类对象组成的 list for authenticator in self.authenticators: try: # 认证器(对象)调用认证方法authenticate(认证类对象self, request请求对象) # 返回值:登陆的用户与认证的信息组成的 tuple # 该方法被try包裹,代表该方法会抛异常,抛异常就代表认证失败 user_auth_tuple = authenticator.authenticate(self) except exceptions.APIException: self._not_authenticated() raise # 返回值的处理 if user_auth_tuple is not None: self._authenticator = authenticator # 如何有返回值,就将 登陆用户 与 登陆认证 分别保存到 request.user、request.auth self.user, self.auth = user_auth_tuple return # 如果返回值user_auth_tuple为空,代表认证通过,但是没有 登陆用户 与 登陆认证信息,代表游客 self._not_authenticated() 4) 权限组件 self.check_permissions(request) 认证细则: def check_permissions(self, request): # 遍历权限对象列表得到一个个权限对象(权限器),进行权限认证 for permission in self.get_permissions(): # 权限类一定有一个has_permission权限方法,用来做权限认证的 # 参数:权限对象self、请求对象request、视图类对象 # 返回值:有权限返回True,无权限返回False if not permission.has_permission(request, self): self.permission_denied( request, message=getattr(permission, 'message', None) ) 自定义认证类 ...

2019年10月21日 · 3 分钟

【DRF】视图家族

视图类传递参数给序列化类 1)在视图类中实例化序列化对象时,可以设置context内容 2)在序列化类中的局部钩子、全局钩子、create、update方法中,都可以用self.context访问视图类传递过来的内容 需求: 1) 在视图类中,可以通过request得到登陆用户request.user 2) 在序列化类中,要完成数据库数据的校验与入库操作,可能会需要知道当前的登陆用户,但序列化类无法访问request 3) 在视图类中实例化序列化对象时,将request对象传递进去 视图层:views.py class Book(APIView): def post(self, request, *args, **kwargs): book_ser = serializers.BookModelSerializer(data=request_data,context={'request':request}) book_ser.is_valid(raise_exception=True) book_result = book_ser.save() return Response({ 'status': 0, 'msg': 'ok', 'results': serializers.BookModelSerializer(book_result).data }) 序列化层:serializer.py class BookModelSerializer(ModelSerializer): class Meta: model = models.Book fields = ('name', 'price') def validate_name(self, value): print(self.context.get('request').method) return value 二次封装Response类 Response({ 'status': 0, 'msg': 'ok', 'results': [], 'token': '' # 有这样的额外的key-value数据结果 },status=http_status,headers=headers,exception=True|False) APIResponse() => Response({'status': 0,'msg': 'ok'}) from rest_framework.response import Response class APIResponse(Response): def __init__(self, data_status=0, data_msg='ok', results=None, http_status=None, headers=None, exception=False, **kwargs): # data的初始状态:状态码与状态信息 data = { 'status': data_status, 'msg': data_msg, } # data的响应数据体 # results可能是False、0等数据,这些数据某些情况下也会作为合法数据返回 if results is not None: data['results'] = results # data响应的其他内容 # if kwargs is not None: # for k, v in kwargs.items(): # setattr(data, k, v) data.update(kwargs) super().__init__(data=data, status=http_status, headers=headers, exception=exception) 视图家族 ...

2019年10月21日 · 3 分钟

【DRF】接口/CBV生命周期

DRF框架 全称:Django-rest framework 知识点 """ 1、接口:什么是接口、restful接口规范 2、CBV生命周期源码 - 基于restful规范下的CBV接口 3、请求组件、解析组件、响应组件 4、序列化组件(灵魂) 5、三大认证(重中之重):认证、权限(权限六表)、频率 6、其他组件:过滤、筛选、排序、分页、路由 """ # 难点:源码分析 接口 """ 接口:联系两个物质的媒介,完成信息交互 web程序中:联系前台页面与后台数据库的媒介 web接口组成: url:长得像放回数据的url链接 请求参数:前台按照指定的key提供数据给后台 响应数据:后台与数据库交互后将数据反馈给前台 """ restful接口规范 接口规范:就是为了采用不同的后台语言,也能使用同样的接口获取到同样的数据 如何写接口:接口规范是规范化书写接口,写接口要写url、响应数据 注:如果将请求参数也纳入考量范围,那就是在写接口文档 两大部分: url 1) 用api关键字表示接口url api.baidu.com | www.baidu.com/api 2) 接口数据安全性决定优先选择https协议 3) 如果一个接口有多版本存在,需要在url中标识体现 api.baidu.com/v1/... | api.baidu.com/v2/... 4) 接口操作的数据源称之为 资源,在url中一般采用资源复数形式,一个接口可以概括对该资源的多种操作方式 api.baidu.com/books | api.baidu.com/books/(pk) 5) 请求方式有多种,用一个url处理如何保证不混乱 - 通过请求方式标识操作资源的方式 /books get 获取所有 /books post 增加一个(多个) /books/(pk) delete 删除一个 /books/(pk) put 整体更新一个 /books/(pk) patch 局部更新一个 6) 资源往往涉及数据的各种操作方式 - 筛选、排序、限制 api.baidu.com/books/?search=西&ordering=-price&limit=3 响应数据 ...

2019年10月17日 · 4 分钟

【DRF】解析/异常/响应模块/序列化组件

解析模块 为什么要配置解析模块 """ 1)drf给我们通过了多种解析数据包方式的解析类 2)我们可以通过配置来控制前台提交的哪些格式的数据后台在解析,哪些数据不解析 3)全局配置就是针对每一个视图类,局部配置就是针对指定的视图来,让它们可以按照配置规则选择性解析数据 """ 源码入口 # APIView类的dispatch方法中 request = self.initialize_request(request, *args, **kwargs) # 点进去 # 获取解析类 parsers=self.get_parsers(), # 点进去 # 去类属性(局部配置) 或 配置文件(全局配置) 拿 parser_classes return [parser() for parser in self.parser_classes] 全局配置:项目settings.py文件 REST_FRAMEWORK = { # 全局解析类配置 'DEFAULT_PARSER_CLASSES': [ 'rest_framework.parsers.JSONParser', # json数据包 'rest_framework.parsers.FormParser', # urlencoding数据包 'rest_framework.parsers.MultiPartParser' # form-date数据包 ], } 局部配置:应用views.p的具体视图类 from rest_framework.parsers import JSONParser class Book(APIView): # 局部解析类配置,只要json类型的数据包才能被解析 parser_classes = [JSONParser] pass 异常模块 ...

2019年10月17日 · 4 分钟

【DRF】序列化/反序列/序列化与反序列整合

环境配置 配置:settings.py INSTALLED_APPS = [ # ... 'rest_framework', ] DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'dg_proj', 'USER': 'root', 'PASSWORD': '123', } } """ 任何__init__文件 import pymysql pymysql.install_as_MySQLdb() """ LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = True USE_TZ = False MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 路由 # 主 from django.conf.urls import url, include from django.contrib import admin from django.views.static import serve from django.conf import settings urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^api/', include('api.urls')), url(r'^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}), ] # 子 from django.conf.urls import url from . import views urlpatterns = [ ] 多表设计 ...

2019年10月17日 · 6 分钟

【vue】项目配置

vue项目环境搭建 node ~~ python: node是用c++编写用来运行js代码的 npm(cnpm) ~~ pip: npm是一个终端应用商城,可以换国内源cnpm vue ~~ django: vue是用来搭建vue前端项目的 1)安装node 官网下载安装包,傻瓜式安装:https://nodejs.org/zh-cn/ 2)换源安装cnpm : npm install -g cnpm – registry=https://registry.npm.taobao.org 3)安装vue项目脚手架 : cnpm install -g @vue/cli 注:2或3终端安装失败时,可以清空 npm缓存 再重复执行失败的步骤 npm cache clean –force vue项目创建 进入存放项目的目录 : cd *** 创建项目 : vue create 项目名 项目初始化 pycharm配置并启动vue项目 用pycharm打开vue项目 添加配置npm启动 vue项目目录结构分析 ├── v-proj | ├── node_modules // 当前项目所有依赖,一般不可以移植给其他电脑环境 | ├── public | | ├── favicon.ico // 标签图标 | | └── index.html // 当前项目唯一的页面 | ├── src | | ├── assets // 静态资源img、css、js | | ├── components // 小组件 | | ├── views // 页面组件 | | ├── App.vue // 根组件 | | ├── main.js // 全局脚本文件(项目的入口) | | ├── router.js // 路由脚本文件(配置路由 url链接 与 页面组件的映射关系) | | └── store.js // 仓库脚本文件(vuex插件的配置文件,数据仓库) | ├── README.md └ └── **配置文件 vue组件(.vue文件) ...

2019年10月10日 · 4 分钟

【vue】条件循环/计算属性/属性监听

条件指令 1)两种都可以控制标签的显隐,绑定的值是布尔类型值,当都隐藏标签时 v-if是不渲染标签 v-show以 display:none 方式渲染 <div id="app"> <p v-if="isShow">if条件指令</p> <p v-show="isShow">show条件指令</p> </div> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { isShow: false, } }) </script> 2)v-if/v-else-if/v-else 一组分支上成立,分支会屏蔽下方所有分支,else分支没有条件,在所有分支不成立后才显示 <style> .box { width: 400px; height: 300px; } .r { background-color: red; } .y { background-color: yellow } .b { background-color: blue; } .active { background-color: pink; } </style> <div id="app"> <div class="em"> <p> <button @click="changeBox('rBox')" :class="{active: showName == 'rBox'}">红</button> <button @click="changeBox('yBox')" :class="{active: showName == 'yBox'}">黄</button> <button @click="changeBox('bBox')" :class="{active: showName == 'bBox'}">蓝</button> </p> <p> <button @click="changeBox('rBox')" :class="showName == 'rBox' ? 'active' : ''">红</button> <button @click="changeBox('yBox')" :class="showName == 'yBox' ? 'active' : ''">黄</button> <button @click="changeBox('bBox')" :class="showName == 'bBox' ? 'active' : ''">蓝</button> </p> <div class="box r" v-if="showName == 'rBox'"></div> <div class="box y" v-else-if="showName == 'yBox'"></div> <div class="box b" v-else></div> </div> </div> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { showName: 'rBox' }, methods: { changeBox(name) { this.showName = name; } } }) </script> ...

2019年10月9日 · 3 分钟

【vue】组件

********组件 1)组件:一个包含html、css、js独立的集合体,这样的集合体可以完成页面结构的代码复用 2)组件分为根组件、全局组件与局部组件 根组件:所有被new Vue()产生的组件,在项目开发阶段,一个项目只会出现一个根组件 全局组件:不用注册,就可以成为任何一个组件的字组件 局部组件:必须注册,才可以成为注册该局部组件的子组件 3)每一个组件都有自身的html结构,css样式,js逻辑 每一个组件其实都有自己的template,就是用来标识自己html结构的 template模板中有且只有一个根标签 根组件一般不提供template,就由挂载点的真实DOM提供html结构 4)除根组件的其他组件,数据要有局部作用域,保证组件复用是,各组件间数据的独立性 5)在多组件共处时,在哪个组件模板中出现的变量,由当前组件提供 局部组件 1)创建局部组件 2)在父组件中注册该局部组件 3)在父组件的template模板中渲染该局部组件 <style> .box { box-shadow: 0 3px 5px 0 #666; width: 240px; height: 300px; text-align: center; padding: 20px 0; float: left; margin: 5px; } .box img { width: 200px; } </style> <div id="app"> <!--<mcc></mcc>--> <local-tag></local-tag> <local-tag></local-tag> </div> <script src="js/vue.js"></script> <script> let localTag = { template: ` <div class="box"> <img src="img/666.jpg" alt=""> <h3>凤哥</h3> <p>马叉虫❤马叉虫</p> </div> ` }; new Vue({ el: '#app', components: { // mcc: localTag, // localTag, 'local-tag': localTag, } }) </script> 全局组件 ...

2019年10月9日 · 3 分钟

【vue】模板语法

vue导读 1)vue框架是前台框架,常见的前台框架有:Angular、React、Vue 2)vue是结合其他框架的优点:轻量级、中文API、数据驱动、双向绑定、MVVM设计模式、支持组件化开发、单页面应用 MVVM设计模式:MV数据到视图一层数据处理,向后台请求数据渲染页面;VM视图再到数据一层数据处理,前台获取的用户数据到后台。 3)vue环境,本地导入与cdn导入 4)vue是js渐进式框架 根据开发需求,可以决定vue框架控制项目的具体方位:可以为一个标签,也可以为一个页面,甚至可以为整个项目 实例成员-挂载点 1)vue通过挂载点与html页面结构建立关联 2)html与body不能作为挂载点 3)一个vue对象挂载点只会索引一个匹配结果,所以挂载点一般用id标识 el:实例 <div id="wrap"> {{ }} <hr> <div class="main"> {{ }} </div> <hr> <div class="main"> {{ }} </div> </div> <script src="js/vue.js"></script> <script> new Vue({ el: '#wrap' // el表示挂载点 }) </script> //实例与页面挂载点一一对应 //一个页面中可以出现多个实例对应多个挂载点 //实例只操作挂载点内部内容 js对象(字典)补充 let b = 20; let dic = { a: 10, // 字典本身就是对象,key都是字符串形式可以省略引号 b // 值为变量时,且与key同名,可以简写 }; console.log(dic) 实例成员-数据 1)用实例成员data为vue环境提供数据,数据采用字典{}形式 2)在插值表达式{{}}中,直接书写数据的key来访问数据 {{}}是插值表达式,中间出现的info是vue变量 插值表达式内可以直接做简单的数学运算 复杂的运算就需要借助过滤器 ...

2019年10月8日 · 5 分钟

【Django】中间件/Auth模块

Django中间件 Django中间件类似于Django的保安。请求的时候需要先经过中间件才能到达Django后端(urls,views,templates,models),响应走的时候也需要经过中间件才能到达web服务网关接口。 Django默认的七个中间件 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] 我们点进去几个组件查看源码: class SecurityMiddleware(MiddlewareMixin): def __init__(self, get_response=None): pass def process_request(self, request): path = request.path.lstrip("/") if (self.redirect and not request.is_secure() and not any(pattern.search(path) for pattern in self.redirect_exempt)): host = self.redirect_host or request.get_host() return HttpResponsePermanentRedirect("https://%s%s" % (host, request.get_full_path())) def process_response(self, request, response): ... return response class CsrfViewMiddleware(MiddlewareMixin): def process_request(self, request): pass def process_view(self, request, callback, callback_args, callback_kwargs): ... return self._accept(request) def process_response(self, request, response): ... return response class AuthenticationMiddleware(MiddlewareMixin): def process_request(self, request): assert hasattr(request, 'session'), ( "The Django authentication middleware requires session middleware " "to be installed. Edit your MIDDLEWARE%s setting to insert " "'django.contrib.sessions.middleware.SessionMiddleware' before " "'django.contrib.auth.middleware.AuthenticationMiddleware'." ) % ("_CLASSES" if settings.MIDDLEWARE is None else "") request.user = SimpleLazyObject(lambda: get_user(request)) 不难发现一些规律: ...

2019年9月25日 · 3 分钟