路由系统
有名分组
from flask import Flask
app=Flask(__name__)
@app.route('/<int:nid>',strict_slashes=False)
def index(nid):
print(nid)
return 'ok'
#对URL最后的 / 符号是否严格要求
strict_slashes = None
'''
@app.route('/index', strict_slashes=False) 非严格模式
#访问http://www.xx.com/index/ 或http://www.xx.com/index均可
@app.route('/index', strict_slashes=True) 严格模式
#仅访问http://www.xx.com/index
'''
#重定向到指定地址
redirect_to = None,
'''
@app.route('/index/<int:nid>', redirect_to='/home/<nid>')
'''
CBV
from flask import Flask,views
app=Flask(__name__)
class IndexView(views.View):
methods=['GET']
def dispatch_request(self):
print('index')
return 'index123'
app.add_url_rule('/index1,view_func=IndexView.as_view(name='index')') # 优先找endpoint=''名字,没有找as_view中name
if __name__='__main__':
app.run()
重写dispatch分发
class IndexView(views.MethodView):
methods = ['GET']
#cbv添加装饰,用这个,我们看as_view中就知道了
decorators = [auth, ]
def get(self):
return 'Index.GET'
def post(self):
return 'Index.POST'
#如果我们继承了MethodView,他帮我们重写了,dispatch_request方法,他给我们做了一个分发,通过请求,来执行不同的函数
app.add_url_rule('/index', view_func=IndexView.as_view(name='index')) # name=endpoint
正则
# 1.写类:继承BaseConverter
# 2.注册:app.url_map.converters['regex'] = RegexConverter
# 3.使用:@app.route('/index/<regex('d+'):nid>') 正则表达式会当作第二个参数传递到类中
from flask import Flask, views, url_for
from werzeug.routing import BaseConverter
app = Flask(import_name=__name__)
class RegexConverter(BaseConverter):
"""
自定义URL匹配正则表达式
"""
def __init__(self, map, regex):
super(RegexConverter, self).__init__(map)
self.regex = regex
def to_python(self, value):
"""
路由匹配时,匹配成功后传递给视图函数中参数的值
"""
return int(value)
def to_url(self, value):
"""
使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
"""
val = super(RegexConverter, self).to_url(value)
return val
# 添加到flask中
app.url.map.converters['regex'] = RegexConverter
@app.route('/index/<regex("d+"):nid>')
def index(nid):
print(url_for('index', nid='888'))
return 'Index'
if __name__ = '__main__':
app.run()
模板
前端页面渲染变量
'''
模板里面
渲染变量
{{}}-->和django一样
{% for k,v in dict.item()%}
{{v.name}}
{{v.get("name")}}
{{v['name']}}
{% endfor %}
'''
# <a>{{url_for("l1")}}</a> --> '/login',前端页面反向解析视图函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>用户列表</h1>
<table>
{% for k,v in user_dict.items() %}
<tr>
<td>{{k}}</td>
<td>{{v.name}}</td>
<td>{{v['name']}}</td>
<td>{{v.get('name')}}</td>
<td><a href="/detail/{{k}}">查看详细</a></td>
</tr>
{% endfor %}
</table>
</body>
</html>
后端
'''
methods=["GET","POST]
/detail/<int:nid>
nid会当做参数传给我们的视图函数
我们给模板传值的必须是关键字传值
url_for()做反向解析,填的是endpoint的值,如果要跳转的视图没有指定endpoint,就用函数名
'''
USERS = {
1:{'name':'张三','age':18,'gender':'男','text':"道路千万条"},
2:{'name':'李四','age':28,'gender':'男','text':"安全第一条"},
3:{'name':'王五','age':18,'gender':'女','text':"行车不规范"},
}
@app.route('/detail/<int:nid>',methods=['GET'])
def detail(nid):
info = USERS.get(nid)
return render_template('detail.html',info=info)
@app.route('/index',methods=['GET'])
def index():
# return redirect('/login')
url = url_for('l1')
return redirect(url)
#return render_template('index.html',user_dict=USERS)
@app.route('/login',methods=['GET','POST'],endpoint='l1')
def login():
if request.method == "GET":
return render_template('login.html')
else:
# request.query_string
user = request.form.get('user')
pwd = request.form.get('pwd')
if user == 'cxw' and pwd == '123':
return redirect('http://www.baidu.com')
return render_template('login.html',error='用户名或密码错误')
# flask中Markup(<h1>哇!</h1>)等价django中的mark_safe('<h1>哇!</h1>'),防止前端页面xss攻击{{ | safe}}
def func1(a,b):
# return (f"<h1>蔡徐坤{a},{b}</h1>")
return Markup(f"<h1>蔡徐坤{a},{b}</h1>")
@app.route("/test")
def py_test():
return render_template('test.html', error=func1)
if __name__ == '__main__':
app.run()
请求响应
'''
获取当前请求的内容
1 先要导入request
2 直接用request.方法,属性
返回的时候,如果需要设置额外的响应参数,比如cookie,heard
1 response=make_response(四剑客)
2 response.设置属性=“属性值”
3 return response
'''
from flask import Flask
from flask import request
from flask import render_template
from flask import redirect
from flask import make_response
app = Flask(__name__)
@app.route('/login.html', methods=['GET', "POST"])
def login():
# 请求相关信息
# request.method 提交的方法
print("request.method",request.method)
# request.args get请求提及的数据
print("request.args", request.args)
# request.form post请求提交的数据
# request.values post和get提交的数据总和
# request.cookies 客户端所带的cookie
# request.headers 请求头
# request.path 不带域名,请求路径
# request.full_path 不带域名,带参数的请求路径
# request.script_root
# request.url 带域名带参数的请求路径
# request.base_url 带域名请求路径
# request.url_root 域名
# request.host_url 域名
# request.host 127.0.0.1:500
# request.files
# obj = request.files['the_file_name']
# obj.save('/var/www/uploads/' + secure_filename(f.filename))
# 响应相关信息
# return "字符串"
# return render_template('html模板路径',**{})
# return redirect('/index.html')
#return jsonify({'k1':'v1'})
# response = make_response(render_template('index.html'))
# response是flask.wrappers.Response类型
# response.delete_cookie('key')
# response.set_cookie('key', 'value')
# response.headers['X-Something'] = 'A value'
# return response
response1=make_response(render_template('test.html'))
#response1.set_cookie('key_sss', 'valuessbbsd')
# response1.delete_cookie('key_sss')
response1.headers['sb'] = 'asdas'
return response1
if __name__ == '__main__':
app.run()
session
# 设置:session['username'] = 'xxx'
# 在django中发什么三件事,1,生成一个随机的字符串 2 往数据库存 3 写入cookie返回浏览器
# 在flask中他没有数据库,但session是怎样实现的?
# 生成一个密钥写入这个cookie,然后下次请求的时候,通过这个cookie解密,然后赋值给session
#我们通过app.session_interface来查看
# 删除:session.pop('username', None)
# session源码的执行流程
"""
-save_seesion
-响应的时候,把session中的值加密序列化放到了cookie中,返回到浏览器中
-open_session
-请求来了,从cookie中取出值,反解,生成session对象,以后在视图函数中直接用sessoin就可以了。
"""
from flask import Flask,session
app = Flask(__name__)
app.debug=True
app.secret_key="ajsdklas" # 设置密钥
app.config['SESSION_COOKIE_NAME']="session_key"
# app.session_interface
@app.route("/")
def index():
session['name']="sb"
return "ok"
@app.route("/test")
def test():
print(session['name'])
return "ok1"
if __name__ == '__main__':
app.run()
闪现flash
'''
1 设置flash
1.1 flash("要传递的值",category="分类的名称"),如果不传默认是message
本质:session['_flash']
2取flash设置的值我们用get_flashed_messages
2.1 get_flashed_messages(with_categories=False, category_filter=()),
2.1.1如果不传递 category_filter,取出上面存储的所有分类传递的值
2.1.2如果不传with_categories就只取值,不取分类的名字,如果传值,就获取 分类名和分类值
3 这个flash只能一个视图函数中取,只要有一个视图函数取过了,那其他视图函数就不能获取
本质:session.pop("_flash")
3.1 但是在同一个视图函数里面可以无限的取值
'''
from flask import Flask,flash,get_flashed_messages,request,redirect
app = Flask(__name__)
app.debug=True
app.secret_key = 'asdfasdf'
@app.route('/index')
def index():
# 从某个地方获取设置过的所有值,并清除。
#flash('超时错误',category="x1")
flash("它过来了,你要小心")
flash("我是第二个",category="ss")
return "ssdsdsdfsd"
# return redirect('/error')
@app.route('/error')
def error():
"""
展示错误信息
:return:
如果get_flashed_messages(with_category=True)
"""
#data = get_flashed_messages(category_filter=['x1'])
data=get_flashed_messages(with_categories=True,category_filter=['ss'])
data1 = get_flashed_messages(with_categories=True, category_filter=['ss'])
print(type(data))
print(data1)
return "错误信息:%s" %(data,)
if __name__ == '__main__':
app.run()
请求扩展
"""
1 before_request 请求之前
1.1可写多个befor_request函数
1.2而且是从上往下执行的
1.3 一旦有返回值,请求的视图函数不会执行,已经剩下的befor_request不会执行
2 after_request 请求之后
2.1可以写多个after_request函数
2.2 所有的after_request是从下往上执行,和befor_request相反
2.3 无论 befor_request有没有返回值,我的after_request都会执行
2.4 必须接收response,而且必须返回response
3 before_first_request 是我项目启动后,接受到的第一个请求,会执行该函数,后面就不会在执行
4 teardown_request(e)
4.1 这是e 是接收我服务器抛出的异常
4.2 无论我服务器有没有错误,都会执行该函数
4.3 虽然能接收异常,但是没有办法处理异常
5 errorhandler(500)
5.1 参数的中值为错误码
5.2 当服务器抛出对应状态码的异常,就会执行该函数
5.3 并且该函数可以处理异常,让用户无法感知,服务器错误
5.4 每一个错误码,都需要一个对应的函数进行处理
"""
# 第一次请求时,跟浏览器无关
@app.before_first_request
def first():
pass
# 基于它做用户登录认证
# 类比django中间件中的process_request,在请求收到之前绑定一个函数做一些事情
@app.before_request
def process_request(*args,**kwargs):
if request.path == '/login':
return None
user = session.get('user_info')
if user:
return None
return redirect('/login')
# 类比django中间件中的process_response,每一个请求之后绑定一个函数,如果请求没有异常
@app.after_request
def process_response1(response):
print('process_response1 走了')
return response
# 每一个请求之后绑定一个函数,即使遇到了异常
@app.teardown_request
def ter(e):
pass
# 全局前端页面都可以获取数据
@app.template_global()
def sb(a1, a2):
return a1 + a2
#{{sb(1,2)}}
# 过滤器
@app.template_filter()
def db(a1, a2, a3):
return a1 + a2 + a3
#{{ 1|db(2,3)}}
中间件
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Hello World!'
# 模拟中间件
class Md(object):
def __init__(self,old_wsgi_app):
self.old_wsgi_app = old_wsgi_app
def __call__(self, environ, start_response):
print('开始之前')
ret = self.old_wsgi_app(environ, start_response)
print('结束之后')
return ret
if __name__ == '__main__':
#1我们发现当执行app.run方法的时候,最终执行run_simple,最后执行app(),也就是在执行app.__call__方法
#2 在__call__里面,执行的是self.wsgi_app().那我们希望在执行他本身的wsgi之前做点事情。
#3 所以我们先用Md类中__init__,保存之前的wsgi,然后我们用将app.wsgi转化成Md的对象。
#4 那执行新的的app.wsgi_app,就是执行Md的__call__方法。
#把原来的wsgi_app替换为自定义的,
app.wsgi_app = Md(app.wsgi_app)
app.run()