目录html
1.大而全的一个web框架 采用的是MVT模式 入手简单 2.Django的卖点是超高的开发效率,其性能扩展有限;采用Django的项目,在流量达到必定规模后,都须要对其进行重构,才能知足性能的要求。 3.Django中的ORM很是方便,作简单的对象定义,它就能自动生成数据库结构、以及全功能的管理后台。 4.Django内置的ORM跟框架内的其余模块耦合程度高。应用程序必须使用Django内置的ORM, 5.Django适用的是中小型的网站,或者是做为大型网站快速实现产品雏形的工具。 Django模板的设计哲学是完全的将代码、样式分离; Django从根本上杜绝在模板中进行编码、处理数据的可能
用户请求进来先走到 wsgi 而后将请求交给 jango的中间件 穿过django中间件(方法是process_request) 接着就是 路由匹配 路由匹配成功以后就执行相应的 视图函数 在视图函数中能够调用orm作数据库操做 再从模板路径 将模板拿到 而后在后台进行模板渲染 模板渲染完成以后就变成一个字符串 再把这个字符串通过全部中间件(方法:process_response) 和wsgi 返回给用户
MVC:model 模型、view(视图)、controller(控制器) MTV:model、tempalte、view
.Admin是对model中对应的数据表进行增删改查提供的组件 .model组件:负责操做数据库 .form组件:1.生成HTML代码2.数据有效性校验3校验信息返回并展现 .ModelForm组件即用于数据库操做,也可用于用户请求的验证
当请求一个页面时, Django会创建一个包含请求元数据的 HttpRequest 对象. 当Django 加载对应的视图时, HttpRequest对象将做为视图函数的第一个参数. 每一个视图会返回一个HttpResponse对象.
websocket是给浏览器新建的一套(相似与http)协议,协议规定:(\r\n分割)浏览器和服务器链接以后不断开, 以此完成:服务端向客户端主动推送消息。 websocket协议额外作的一些操做 握手 ----> 链接钱进行校验 加密 ----> payload_len=127/126/<=125 --> mask key 本质 建立一个链接后不断开的socket 当链接成功以后: 客户端(浏览器)会自动向服务端发送消息,包含: Sec-WebSocket-Key: iyRe1KMHi4S4QXzcoboMmw== 服务端接收以后,会对于该数据进行加密:base64(sha1(swk + magic_string)) 构造响应头: HTTP/1.1 101 Switching Protocols\r\n Upgrade:websocket\r\n Connection: Upgrade\r\n Sec-WebSocket-Accept: 加密后的值\r\n WebSocket-Location: ws://127.0.0.1:8002\r\n\r\n 发给客户端(浏览器) 创建:双工通道,接下来就能够进行收发数据 发送数据是加密,解密,根据payload_len的值进行处理 payload_len <= 125 payload_len == 126 payload_len == 127 获取内容: mask_key 数据 根据mask_key和数据进行位运算,就能够把值解析出来。
客户端向服务端发送消息时,会有一个'sec-websocket-key'和'magic string'的随机字符串(魔法字符串) # 服务端接收到消息后会把他们链接成一个新的key串,进行编码、加密,确保信息的安全性
django 大而全的框架它的内部组件比较多,内部提供:ORM、Admin、中间件、Form、ModelForm、Session、 缓存、信号、CSRF;功能也都挺完善的 flask ,微型框架,内部组件就比较少了,可是有不少第三方组件来扩展它, 好比说有那个wtform(与django的modelform相似,表单验证)、flask-sqlalchemy(操做数据库的)、 flask-session、flask-migrate、flask-script、blinker可扩展强,第三方组件丰富。因此对他自己来讲有那种短小精悍的感受 - tornado,异步非阻塞。 django和flask的共同点就是,他们2个框架都没有写socket,因此他们都是利用第三方模块wsgi。 可是内部使用的wsgi也是有些不一样的:django自己运行起来使用wsgiref,而flask使用werkzeug wsgi 还有一个区别就是他们的请求管理不太同样:django是经过将请求封装成request对象,再经过参数传递,而flask是经过上下文管理机制 Tornado 是一个轻量级的Web框架,异步非阻塞+内置WebSocket功能。 '目标':经过一个线程处理N个并发请求(处理IO)。 内部组件 #内部本身实现socket #路由系统 #视图 #模板 #cookie #csrf
django中能够经过channel实现websocket
jango中提供了6种缓存方式: 开发调试(不加缓存) 内存 文件 数据库 Memcache缓存(python-memcached模块) Memcache缓存(pylibmc模块) 安装第三方组件支持redis: django-redis组件 设置缓存 # 全站缓存(中间件) MIDDLEWARE_CLASSES = ( ‘django.middleware.cache.UpdateCacheMiddleware’, #第一 'django.middleware.common.CommonMiddleware', ‘django.middleware.cache.FetchFromCacheMiddleware’, #最后 ) # 视图缓存 from django.views.decorators.cache import cache_page import time @cache_page(15) #超时时间为15秒 def index(request): t=time.time() #获取当前时间 return render(request,"index.html",locals()) # 模板缓存 {% load cache %} <h3 style="color: green">不缓存:-----{{ t }}</h3> {% cache 2 'name' %} # 存的key <h3>缓存:-----:{{ t }}</h3> {% endcache %}
pip install django-redis apt-get install redis-serv 在setting添加配置文件 CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", # 缓存类型 "LOCATION": "127.0.0.1:6379", # ip端口 "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", # "CONNECTION_POOL_KWARGS": {"max_connections": 100} # 链接池最大链接数 # "PASSWORD": "密码", } } } 使用 from django.shortcuts import render,HttpResponse from django_redis import get_redis_connection def index(request): # 根据名字去链接池中获取链接 conn = get_redis_connection("default") conn.hset('n1','k1','v1') # 存数据 return HttpResponse('...')
同源:域名、协议、端口彻底相同。 跨域:域名、协议、端口有其中的同样不一样。 什么是同源策略 同协议、同domain(或ip)、同端口,视为同一个域,一个域内的脚本仅仅具备本域内的权限。 理解:本域脚本只能读写本域内的资源,而没法访问其它域的资源。这种安全限制称为同源策略。 前端解决跨域访问的经常使用方式 1.jsonp 2.iframe 元素会建立包含另一个文档的内联框架(即行内框架) 3.代理:如vue-cli项目中的config/index.js文件中的proxyTable设置所要跨域访问的地址 ors跨域(场景:先后端分离时,本地测试开发时使用) 若是网站之间存在跨域,域名不一样,端口不一样会致使出现跨域,但凡出现跨域,浏览器就会出现同源策略的限制 解决:在咱们的服务端给咱们响应数据,加上响应头---> 在中间件加的 设想这样一种状况:A网站是一家银行,用户登陆之后,又去浏览其余网站。若是其余网站能够读取A网站的 Cookie,会发生什么? 很显然,若是 Cookie 包含隐私(好比存款总额),这些信息就会泄漏。更可怕的是,Cookie 每每用来保存用户的登陆状态,若是用户没有退出登陆,其余网站就能够冒充用户,随心所欲。由于浏览器同时还规定,提交表单不受同源政策的限制。 因而可知,"同源政策"是必需的,不然 Cookie 能够共享,互联网就毫无安全可言了。 https://www.cnblogs.com/kiscon/p/8633076.html
分类: 1** 信息,服务器收到请求,须要请求者继续执行操做 2** 成功,操做被成功接收并处理 3** 重定向,须要进一步的操做以完成请求 4** 客户端错误,请求包含语法错误或没法完成请求 5** 服务器错误,服务器在处理请求的过程当中发生了错误 常见的状态码 200 -请求成功 202 -已接受请求,还没有处理 204 -请求成功,且不需返回内容 301 - 资源(网页等)被永久转移到其余url 400 - 请求的语义或是参数有错 403 - 服务器拒绝请求 404 - 请求资源(网页)不存在 500 - 内部服务器错误 502 - 网关错误,通常是服务器压力过大致使链接超时 503 - 因为超载或系统维护,服务器暂时的没法处理客户端的请求。
- user-agent这个头信息识别发出请求的浏览器或其余客户端,并能够向不一样类型的浏览器返回不一样的内容。 - host这个头信息指定原始的 URL 中的主机和端口。 - referer 这个头信息指示所指向的 Web 页的 URL。例如,若是您在网页 1,点击一个连接到网页 2,当浏览器请求网页 2 时,网页 1 的 URL 就会包含在 Referer 头信息中。 - cookie 这个头信息把以前发送到浏览器的 cookies 返回到服务器。 - content-type
#Http: 80端口 #https: 443端口 # http信息是明文传输,https则是具备安全性的ssl加密传输协议。 #- 自定义证书 - 服务端:建立一对证书 - 客户端:必须携带证书 #- 购买证书 - 服务端: 建立一对证书,。。。。 - 客户端: 去机构获取证书,数据加密后发给我们的服务单 - 证书机构:公钥给改机构
WSGI: web服务器网关接口,是一套协议。用于接收用户请求并将请求进行初次封装,而后将请求交给web框架 实现wsgi协议的模块: 1. wsgiref,本质上就是编写一个socket服务端,用于接收用户请求(django) 2.werkzeug,本质上就是编写一个socket服务端,用于接收用户请求(flask) uwsgi: 与WSGI同样是一种通讯协议,它是uWSGI服务器的独占协议,用于定义传输信息的类型 uWSGI: 是一个web服务器,实现了WSGI协议,uWSGI协议,http协议,
process_request : 请求进来时,权限认证 process_view : 路由匹配以后,可以获得视图函数 process_exception : 异常时执行 process_template_responseprocess : 模板渲染时执行 process_response : 请求有响应时执行
反向解析路由字符串 路由系统中name的做用:反向解析 url(r'^home', views.home, name='home') 在模板中使用:{ % url 'home' %} 在视图中使用:reverse(“home”) 当后期要修改url设置规则时,在不使用name字段的时候,不但要修改urls.py文件中的url路由,还要讲html文件中全部的相同路径进行修改,在实际应用中将会有大量的url路由,这样修改下来将会十分的麻烦。 可是,若是使用name字段只须要在urls.py 文件中将path()中的url路由修改了就好了,html文件中的则不须要修改,由于这种方式下是经过name字段来映射url的,故不用再去修改html文件了。而通常状况下name的值又是不会变化的,故后期修改起来将会十分的方便。
即便不一样的APP使用相同的URL名称,URL的命名空间模式也可让你惟一反转命名的URL。
FBV和CBV本质是同样的 基于函数的视图叫作FBV,基于类的视图叫作CBV 在python中使用CBV的优势: cbv的好处 提升了代码的复用性,可使用面向对象的技术,好比Mixin(多继承) 能够用不一样的函数针对不一样的HTTP方法处理,而不是经过不少 if 判断,提升代码可读性
第一步先引入模块from django.utils.decorators import method_decorator` 第2步 加语法糖@method_decorator(wrapper)` from django.shortcuts import render,HttpResponse from django.views import View from django.utils.decorators import method_decorator def wrapper(func): def inner(*args, **kwargs): print(11111) ret = func(*args, **kwargs) print(22222) return ret return inner # @method_decorator(wrapper,name='get') # 方式3给get加 用的很少 class LoginView(View): @method_decorator(wrapper) #方式1 def get(self,request): print('小小小小') return HttpResponse('登陆成功') def post(self,request): print(request.POST) return HttpResponse('登陆成功')
- 没什么区别,由于他们的本质都是函数。CBV的.as_view()返回的view函数,view函数中调用类的dispatch方法, 在dispatch方法中经过反射执行get/post/delete/put等方法。D 非要说区别的话: - CBV比较简洁,GET/POST等业务功能分别放在不一样get/post函数中。FBV本身作判断进行区分。
request.method ——》 请求的方式 8种 GET POST PUT DELETE OPTIONS request.GET ——》 字典 url上携带的参数 request.POST ——》 字典 form表单经过POST请求提交的数据 request.path_info ——》 URL路径 不带参数 request.body ——》 请求体 request.FILES 上传的文件 {} request.COOKIES cookie request.session session request.META 请求头 redirect 重定向 def cs(request): return redirect('/cs1/') #重定向到url为cs1的地址 def cs1(request): return HttpResponse('666') #返回字符串666 def cs1(request): render(request,'xx.html')#返回html页面
返回QuerySet对象的方法有: all()所有 filter()过滤 exclude() 排除的意思 order_by() reverse() queryset类型的数据来调用,对查询结果反向排序, distinct() values和values_list获得的queryset类型的数据来调用,从返回结果中剔除重复纪录 去重 特殊的QuerySet: values() 返回一个可迭代的字典序列 values_list() 返回一个可迭代的元组序列 返回具体对象的: get() first()第一个 last()最后一个 返回布尔值的方法有: exists() queryset类型的数据来调用,若是QuerySet包含数据,就返回True,不然返回False 返回数字的方法有: count() model对象能够点出来 queryset对象相互转换 只要是返回的queryset类型,就能够继续链式调用queryset类型的其余的查找方法,其余方法也是同样的 <1> all(): 查询全部结果,结果是queryset类型 查询全部的数据 .all方法 返回的是queryset集合 all_objs = models.Student.objects.all() # 相似于列表 -- queryset集合 for i in all_objs: print(i.name) print(all_objs) <2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象,结果也是queryset类型 Book.objects.filter(title='linux',price=100) #里面的多个条件用逗号分开,而且这几个条件必须都成立,是and的关系, models.Student.objects.all().filter(id=7) queryset类型能够调用fitler在过滤 <3> get(**kwargs): 返回与所给筛选条件相匹配的对象,不是queryset类型,是行记录对象,返回结果有且只有一个, 若是符合筛选条件的对象超过一个或者没有都会抛出错误。捕获异常try。 Book.objects.get(id=1) <4> exclude(**kwargs): 排除的意思,它包含了与所给筛选条件不匹配的对象,没有不等于的操做昂,用这个exclude,返回值是queryset类型 Book.objects.exclude(id=6),返回id不等于6的全部的对象,或者在queryset基础上调用,Book.objects.all().exclude(id=6) exclude(**kwargs): 排除,objects控制器和queryset集合均可以调用,返回结果是queryset类型 query = models.Student.objects.exclude(id=1) print(query) query = models.Student.objects.filter(age=38).exclude(id=6) print(query) <5> order_by(*field): 排序 queryset类型的数据来调用,对查询结果排序,默认是按照id来升序排列的,返回值仍是queryset类型 models.Book.objects.all().order_by('price','id') #直接写price,默认是按照price升序排列,按照字段降序排列,就写个负号就好了order_by('-cs'),order_by('price','id')是多条件排序,按照price进行升序,price相同的数据,按照id进行升序 <6> reverse(): queryset类型的数据来调用,对查询结果反向排序,返回值仍是queryset类型 # 只能够排序以后反转 # query = models.Student.objects.all().order_by('id').reverse() # print(query) <7> count(): queryset类型的数据来调用,返回数据库中匹配查询(QuerySet)的对象数量。 <8> first(): queryset类型的数据来调用 ,返回第一条记录结果为model对象类型 Book值 <9> last(): queryset类型的数据来调用,返回最后一条记录,结果为model对象类型 <10> exists(): queryset类型的数据来调用,若是QuerySet包含数据,就返回True,不然返回False 空的queryset类型数据也有布尔值True和False,可是通常不用它来判断数据库里面是否是有数据,若是有大量的数据,你用它来判断,那么就须要查询出全部的数据,效率太差了,用count或者exits 例:all_books = models.Book.objects.all().exists() #翻译成的sql是SELECT (1) AS `a` FROM `app01_book` LIMIT 1,就是经过limit 1,取一条来看看是否是有数据 <11> values(*field): 用的比较多,queryset类型的数据来调用,返回一个ValueQuerySet——一个特殊的QuerySet,运行后获得的并非一系列 model的实例化对象,而是一个可迭代的字典序列,只要是返回的queryset类型,就能够继续链式调用queryset类型的其余的查找方法,其余方法也是同样的。 里面能够加子段显示 <12> values_list(*field): 它与values()很是类似,它返回的是一个元组序列,values返回的是一个字典序列 里面能够加子段显示 <13> distinct(): values和values_list获得的queryset类型的数据来调用,从返回结果中剔除重复纪录 去重,结果仍是queryset 里面不能够传参 显示nanme等等能够用来去重 query = models.Student.objects.all().values('age').distinct() print(query)
def filter(self, *args, **kwargs) # 条件查询(符合条件) # 查出符合条件 # 条件能够是:参数,字典,Q def exclude(self, *args, **kwargs) # 条件查询(排除条件) # 排除不想要的 # 条件能够是:参数,字典,Q
1.使用execute执行自定义的SQL 直接执行SQL语句(相似于pymysql的用法) # 更高灵活度的方式执行原生SQL语句 from django.db import connection cursor = connection.cursor() cursor.execute("SELECT DATE_FORMAT(create_time, '%Y-%m') FROM blog_article;") ret = cursor.fetchall() print(ret) 2.使用extra方法 :queryset.extra(select={"key": "原生的SQL语句"}) 3.使用raw()方法 1.执行原始sql并返回模型 2.依赖model多用于查询
F:主要用来获取原数据进行计算。 同表 字段比较 更新) Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操做。 修改操做也可使用F函数,好比将每件商品的价格都在原价格的基础上增长10 from django.db.models import F from app01.models import Goods Goods.objects.update(price=F("price")+10) # 对于goods表中每件商品的价格都在原价格的基础上增长10元 F查询专门对对象中某列值的操做,不可以使用__双下划线! Q:用来进行复杂查询 Q查询(与或非) Q查询能够组合使用 “&”, “|” 操做符,当一个操做符是用于两个Q的对象,它产生一个新的Q对象, Q对象能够用 “~” 操做符放在前面表示否认,也可容许否认与不否认形式的组合。 Q对象能够与关键字参数查询一块儿使用,不过必定要把Q对象放在关键字参数查询的前面。 Q(条件1) | Q(条件2) 或 Q(条件1) & Q(条件2) 且 Q(条件1) & ~Q(条件2) 非
def bulk_create(self, objs, batch_size=None): # 批量插入 # batch_size表示一次插入的个数 objs = [ models.DDD(name='r11'), models.DDD(name='r22') ] models.DDD.objects.bulk_create(objs, 10)
def defer(self, *fields): models.UserInfo.objects.defer('username','id') 或 models.UserInfo.objects.filter(...).defer('username','id') #映射中排除某列数据 def only(self, *fields): #仅取某个表中的数据 models.UserInfo.objects.only('username','id') 或 models.UserInfo.objects.filter(...).only('username','id')
def filter(self, *args, **kwargs) # 条件查询(符合条件) # 查出符合条件 # 条件能够是:参数,字典,Q def exclude(self, *args, **kwargs) # 条件查询(排除条件) # 排除不想要的 # 条件能够是:参数,字典,Q
方式一:手动使用queryset的using方法 from django.shortcuts import render,HttpResponse from app01 import models def index(request): models.UserType.objects.using('db1').create(title='普通用户') # 手动指定去某个数据库取数据 result = models.UserType.objects.all().using('db1') print(result) return HttpResponse('...') 方式二:写配置文件 class Router1: # 指定到某个数据库取数据 def db_for_read(self, model, **hints): """ Attempts to read auth models go to auth_db. """ if model._meta.model_name == 'usertype': return 'db1' else: return 'default' # 指定到某个数据库存数据 def db_for_write(self, model, **hints): """ Attempts to write auth models go to auth_db. """ return 'default' 再写到配置 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), }, 'db1': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } DATABASE_ROUTERS = ['db_router.Router1',]
def values(self, *fields): # 获取每行数据为字典格式 def values_list(self, *fields, **kwargs): # 获取每行数据为元祖
obj_list里面是列表 列表里有对象 models.Book.objects.bulk_create(obj_list) #批量建立
使用django的信号机制,能够在添加、删除数据先后设置日志记录 pre_init # Django中的model对象执行其构造方法前,自动触发 post_init # Django中的model对象执行其构造方法后,自动触发 pre_save # Django中的model对象保存前,自动触发 post_save # Django中的model对象保存后,自动触发 pre_delete # Django中的model对象删除前,自动触发 post_delete # Django中的model对象删除后,自动触发
db first: 先建立数据库,再更新表模型 code first:先写表模型,再更新数据库 https://www.cnblogs.com/jassin-du/p/8988897.html
一、修改seting文件,在setting里面设置要链接的数据库类型和名称、地址 二、运行下面代码能够自动生成models模型文件 - python manage.py inspectdb 三、建立一个app执行下下面代码: - python manage.py inspectdb > app/models.py
SQL: # 优势: 执行速度快 # 缺点: 编写复杂,开发效率不高 --------------------------------------------------------------------------- ORM: # 优势: 让用户再也不写SQL语句,提升开发效率 能够很方便地引入数据缓存之类的附加功能 # 缺点: 在处理多表联查、where条件复杂查询时,ORM的语法会变得复杂。 没有原生SQL速度快
目的:防止用户直接向服务端发起POST请求 - 用户先发送GET获取csrf token: Form表单中一个隐藏的标签 + token - 发起POST请求时,须要携带以前发送给用户的csrf token; - 在中间件的process_view方法中进行校验。 在html中添加{%csrf_token%}标签
filter : 相似管道,只能接受两个参数第一个参数是|前的数据 simple_tag : 相似函数 一、模板继承:{ % extends 'layouts.html' %} 二、自定义方法 'filter':只能传递两个参数,能够在if、for语句中使用 'simple_tag':能够无线传参,不能在if for中使用 'inclusion_tags':可使用模板和后端数据 三、防xss攻击: '|safe'、'mark_safe'
- 做用: - 对用户请求数据格式进行校验 - 自动生成HTML标签 - 区别: - Form,字段须要本身手写。 class Form(Form): xx = fields.CharField(.) xx = fields.CharField(.) xx = fields.CharField(.) xx = fields.CharField(.) - ModelForm,能够经过Meta进行定义 class MForm(ModelForm): class Meta: fields = "__all__" model = UserInfo - 应用:只要是客户端向服务端发送表单数据时,均可以进行使用,如:用户登陆注册
方式一:重写构造方法,在构造方法中从新去数据库获取值 class UserForm(Form): name = fields.CharField(label='用户名',max_length=32) email = fields.EmailField(label='邮箱') ut_id = fields.ChoiceField( # choices=[(1,'普通用户'),(2,'IP用户')] choices=[] ) def __init__(self,*args,**kwargs): super(UserForm,self).__init__(*args,**kwargs) self.fields['ut_id'].choices = models.UserType.objects.all().values_list('id','title') 方式二: ModelChoiceField字段 from django.forms import Form from django.forms import fields from django.forms.models import ModelChoiceField class UserForm(Form): name = fields.CharField(label='用户名',max_length=32) email = fields.EmailField(label='邮箱') ut_id = ModelChoiceField(queryset=models.UserType.objects.all()) 依赖: class UserType(models.Model): title = models.CharField(max_length=32) def __str__(self): return self.title
在django2.0后,定义外键和一对一关系的时候须要加on_delete选项,此参数为了不两个表里的数据不一致问题,否则会报错: TypeError: __init__() missing 1 required positional argument: 'on_delete' 举例说明: user=models.OneToOneField(User) owner=models.ForeignKey(UserProfile) 须要改为: user=models.OneToOneField(User,on_delete=models.CASCADE) --在老版本这个参数(models.CASCADE)是默认值 owner=models.ForeignKey(UserProfile,on_delete=models.CASCADE) --在老版本这个参数(models.CASCADE)是默认值 参数说明: on_delete有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五个可选择的值 CASCADE:此值设置,是级联删除。 PROTECT:此值设置,是会报完整性错误。 SET_NULL:此值设置,会把外键设置为null,前提是容许为null。 SET_DEFAULT:此值设置,会把设置为外键的默认值。 SET():此值设置,会调用外面的值,能够是一个函数。 通常状况下使用CASCADE就能够了。
contenttype是django的一个组件(app),它能够将django下全部app下的表记录下来 可使用他再加上表中的两个字段,实现一张表和N张表动态建立FK关系。 - 字段:表名称 - 字段:数据行ID 应用:路飞表结构优惠券和专题课和学位课关联
//方式一给每一个ajax都加上上请求头 function Do1(){ $.ajax({ url:"/index/", data:{id:1}, type:'POST', data:{csrfmiddlewaretoken:'{{ csrf_token }}',name:'alex'} success:function(data){ console.log(data); } }); } 方式二:须要先下载jQuery-cookie,才能去cookie中获取token function Do1(){ $.ajax({ url:"/index/", data:{id:1}, type:'POST', headers:{ 'X-CSRFToken':$.cookie('csrftoken') // 去cookie中获取 }, success:function(data){ console.log(data); } }); } 方式三:搞个函数ajaxSetup,当有多的ajax请求,即会执行这个函数 $.ajaxSetup({ beforeSend:function (xhr,settings) { xhr.setRequestHeader("X-CSRFToken",$.cookie('csrftoken')) } }); 函数版本 <body> <input type="button" onclick="Do1();" value="Do it"/> <input type="button" onclick="Do2();" value="Do it"/> <input type="button" onclick="Do3();" value="Do it"/> <script src="/static/jquery-3.3.1.min.js"></script> <script src="/static/jquery.cookie.js"></script> <script> $.ajaxSetup({ beforeSend: function(xhr, settings) { xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken')); } }); function Do1(){ $.ajax({ url:"/index/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); } function Do2(){ $.ajax({ url:"/index/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); } function Do3(){ $.ajax({ url:"/index/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); } </script> </body>
vue-resource的interceptors拦截器的做用正是解决此需求的妙方。 在每次http的请求响应以后,若是设置了拦截器以下,会优先执行拦截器函数,获取响应体,而后才会决定是否把response返回给then进行接收
一、v-if指令:判断指令,根据表达式值得真假来插入或删除相应的值。 二、v-show指令:条件渲染指令,不管返回的布尔值是true仍是false,元素都会存在在html中,只是false的元素会隐藏在html中,并不会删除. 三、v-else指令:配合v-if或v-else使用。 四、v-for指令:循环指令,至关于遍历。 五、v-bind:给DOM绑定元素属性。 六、v-on指令:监听DOM事件。
restful其实就是一套编写接口的'协议',规定如何编写以及如何设置返回值、状态码等信息。 # 最显著的特色: # 用restful: 给用户一个url,根据method不一样在后端作不一样的处理 好比:post建立数据、get获取数据、put和patch修改数据、delete删除数据。 # 不用restful: 给调用者不少url,每一个url表明一个功能,好比:add_user/delte_user/edit_user/ # 固然,还有协议其余的,好比: '版本'来控制让程序有多个版本共存的状况,版本能够放在 url、请求头(accept/自定义)、GET参数 '状态码'200/300/400/500 'url中尽可能使用名词'restful也能够称为“面向资源编程” 'api标示' api.luffycity.com www.luffycity.com/api/
'一个接口经过1次相同的访问,再对该接口进行N次相同的访问时,对资源不造影响就认为接口具备幂等性。' GET, #第一次获取结果、第二次也是获取结果对资源都不会形成影响,幂等。 POST, #第一次新增数据,第二次也会再次新增,非幂等。 PUT, #第一次更新数据,第二次不会再次更新,幂等。 PATCH,#第一次更新数据,第二次不会再次更新,非幂等。 DELTE,#第一次删除数据,第二次不在再删除,幂等。
'远程过程调用协议' 是一种经过网络从远程计算机程序上请求服务,而不须要了解底层网络技术的协议。 进化的顺序: 现有的RPC,而后有的RESTful规范
# 在编写接口时能够不使用django rest framework框架, # 不使用:也能够作,能够用django的CBV来实现,开发者编写的代码会更多一些。 # 使用:内部帮助咱们提供了不少方便的组件,咱们经过配置就能够完成相应操做,如: '序列化'能够作用户请求数据校验+queryset对象的序列化称为json '解析器'获取用户请求数据request.data,会自动根据content-type请求头的不能对数据进行解析 '分页'将从数据库获取到的数据在页面进行分页显示。 # 还有其余组件: '认证'、'权限'、'访问频率控制
#- 路由,自动帮助开发者快速为一个视图建立4个url www.oldboyedu.com/api/v1/student/$ www.oldboyedu.com/api/v1/student(?P<format>\w+)$ www.oldboyedu.com/api/v1/student/(?P<pk>\d+)/$ www.oldboyedu.com/api/v1/student/(?P<pk>\d+)(?P<format>\w+)$ #- 版本处理 - 问题:版本均可以放在那里? - url - GET - 请求头 #- 认证 - 问题:认证流程? #- 权限 - 权限是否能够放在中间件中?以及为何? #- 访问频率的控制 匿名用户能够真正的防止?没法作到真正的访问频率控制,只能把小白拒之门外。 若是要封IP,使用防火墙来作。 登陆用户能够经过用户名做为惟一标示进行控制,若是有人注册不少帐号,则没法防止。 #- 视图 #- 解析器 ,根据Content-Type请求头对请求体中的数据格式进行处理。request.data #- 分页 #- 序列化 - 序列化 - source - 定义方法 - 请求数据格式校验 #- 渲染器
a. 继承APIView(最原始)但定制性比较强 这个类属于rest framework中的顶层类,内部帮助咱们实现了只是基本功能:认证、权限、频率控制, 但凡是数据库、分页等操做都须要手动去完成,比较原始。 class GenericAPIView(APIView) def post(...): pass b.继承GenericViewSet(ViewSetMixin,generics.GenericAPIView) 首先他的路由就发生变化 若是继承它以后,路由中的as_view须要填写对应关系 在内部也帮助咱们提供了一些方便的方法: get_queryset get_object get_serializer get_serializer_class get_serializer_context filter_queryset 注意:要设置queryset字段,不然会抛出断言的异常。 代码 只提供增长功能 只继承GenericViewSet class TestView(GenericViewSet): serialazer_class = xxx def creat(self,*args,**kwargs): pass # 获取数据并对数据 c. 继承 modelviewset --> 快速快发 -ModelViewSet(增删改查全有+数据库操做) -mixins.CreateModelMixin(只有增),GenericViewSet -mixins.CreateModelMixin,DestroyModelMixin,GenericViewSet 对数据库和分页等操做不用咱们在编写,只须要继承相关类便可。 示例:只提供增长功能 class TestView(mixins.CreateModelMixin,GenericViewSet): serializer_class = XXXXXXX *** modelviewset --> 快速开发,复杂点的genericview、apiview
- 如何编写?写类并实现authenticators 请求进来认证须要编写一个类,类里面有一个authenticators方法,咱们能够自定义这个方法,能够定制3类返回值。 成功返回元组,返回none为匿名用户,抛出异常为认证失败。 源码流程:请求进来先走dispatch方法,而后封装的request对象会执行user方法,由user触发authenticators认证流程 - 方法中能够定义三种返回值: - (user,auth),认证成功 - None , 匿名用户 - 异常 ,认证失败 - 流程: - dispatch - 再去request中进行认证处理
# 对匿名用户,根据用户IP或代理IP做为标识进行记录,为每一个用户在redis中建一个列表 { throttle_1.1.1.1:[1526868876.497521,152686885.497521...], throttle_1.1.1.2:[1526868876.497521,152686885.497521...], throttle_1.1.1.3:[1526868876.497521,152686885.497521...], } 每一个用户再来访问时,需先去记录中剔除过时记录,再根据列表的长度判断是否能够继续访问。 '如何封IP':在防火墙中进行设置 -------------------------------------------------------------------------- # 对注册用户,根据用户名或邮箱进行判断。 { throttle_xxxx1:[1526868876.497521,152686885.497521...], throttle_xxxx2:[1526868876.497521,152686885.497521...], throttle_xxxx3:[1526868876.497521,152686885.497521...], } 每一个用户再来访问时,需先去记录中剔除过时记录,再根据列表的长度判断是否能够继续访问。 \如1分钟:40次,列表长度限制在40,超过40则不可访问
Flask自由、灵活,可扩展性强,透明可控,第三方库的选择面广, 开发时能够结合最流行最强大的Python库,
# 依赖jinja2模板引擎 # 依赖werkzurg协议
# blueprint把实现不一样功能的module分开.也就是把一个大的App分割成各自实现不一样功能的module. # 在一个blueprint中能够调用另外一个blueprint的视图函数, 但要加相应的blueprint名.
# Flask组件 flask-session session放在redis flask-SQLAlchemy 如django里的ORM操做 flask-migrate 数据库迁移 flask-script 自定义命令 blinker 信号-触发信号 # 第三方组件 Wtforms 快速建立前端标签、文本校验 dbutile 建立数据库链接池 gevnet-websocket 实现websocket # 自定义Flask组件 自定义auth认证 参考flask-login组件
# a、简单来讲,falsk上下文管理能够分为三个阶段: 一、'请求进来时':将请求相关的数据放入上下问管理中 二、'在视图函数中':要去上下文管理中取值 三、'请求响应':要将上下文管理中的数据清除 # b、详细点来讲: 一、'请求刚进来': 将request,session封装在RequestContext类中 app,g封装在AppContext类中 并经过LocalStack将requestcontext和appcontext放入Local类中 二、'视图函数中': 经过localproxy--->偏函数--->localstack--->local取值 三、'请求响应时': 先执行save.session()再各自执行pop(),将local中的数据清除
# g是贯穿于一次请求的全局变量,当请求进来将g和current_app封装为一个APPContext类, # 再经过LocalStack将Appcontext放入Local中,取值时经过偏函数在LocalStack、local中取值; # 响应时将local中的g数据删除:
RequestContext #封装进来的请求(赋值给ctx) AppContext #封装app_ctx LocalStack #将local对象中的数据维护成一个栈(先进后出) Local #保存请求上下文对象和app上下文对象
# 由于经过维护成列表,能够实现一个栈的数据结构,进栈出栈时只取一个数据,巧妙的简化了问题。 # 还有,在多app应用时,能够实现数据隔离;列表里不会加数据,而是会生成一个新的列表 # local是一个字典,字典里key(stack)是惟一标识,value是一个列表
请求进来时,能够根据URL的不一样,交给不一样的APP处理。蓝图也能够实现。 #app1 = Flask('app01') #app2 = Flask('app02') #@app1.route('/index') #@app2.route('/index2') 源码中在DispatcherMiddleware类里调用app2.__call__, 原理其实就是URL分割,而后将请求分发给指定的app。 以后app也按单app的流程走。就是从app.__call__走。
gevent-websocket
#快速建立前端标签、文本校验;如django的ModelForm
# flask中的信号blinker 信号主要是让开发者但是在flask请求过程当中定制一些行为。 或者说flask在列表里面预留了几个空列表,在里面存东西。 简言之,信号容许某个'发送者'通知'接收者'有事情发生了 @ before_request有返回值,blinker没有返回值 # 10个信号 request_started = _signals.signal('request-started') #请求到来前执行 request_finished = _signals.signal('request-finished') #请求结束后执行 before_render_template = _signals.signal('before-render-template')#模板渲染前执行 template_rendered = _signals.signal('template-rendered')#模板渲染后执行 got_request_exception = _signals.signal('got-request-exception') #请求执行出现异常时执行 request_tearing_down = _signals.signal('request-tearing-down')#请求执行完毕后自动执行(不管成功与否) appcontext_tearing_down = _signals.signal('appcontext-tearing-down')# 请求上下文执行完毕后自动执行(不管成功与否) appcontext_pushed = _signals.signal('appcontext-pushed') #请求app上下文push时执行 appcontext_popped = _signals.signal('appcontext-popped') #请求上下文pop时执行 message_flashed = _signals.signal('message-flashed')#调用flask在其中添加数据时,自动触发