一、.基于装饰器的session访问控制,endpoint路由参数可以解决视图函数重名的情况。
下面我有一个简单的需求,就是一个网站有三个页面,分别是home、index和login界面,用户只有当登陆后才可以正常访问home和index页面,通过装饰器的方法来实现。接下来看代码
from flask import Flask, request, render_template, redirect, Markup, session
app = Flask(__name__)
app.secret_key = "abcdefghijklmn"
def wrapper(f):
def inner(*args, **kwargs):
if session.get("user"):
ret = f(*args, **kwargs)
return ret
else:
return redirect("/login")
return inner
@app.route("/login", methods=("GET","POST"))
def login():
if request.method == "GET":
return render_template("login.html")
if request.method == "POST":
username = request.form.get("username")
session["user"] = username
return "登陆成功"
@app.route("/home", methods=("GET", "POST"))
@wrapper
def home():
return "这是home界面的内容"
@app.route("/index")
def index():
return "我是index界面的内容"
app.run()
当我们只对home视图函数加上认证装饰器时实现了我们的需求,但是如果你给index也加上认证装饰器时你就会发现Flask项目启动不起来了,会报一个这样的错误:
这是因为,当我们对一个以上的视图函数添加了认证装饰器后 ,认证装饰器会将视图函数名替换成装饰器的内层函数名inner,在内存中就会出现视图函数名重复的情况,这样Flask的路由装饰器装饰视图函数时就会报错,解决这个错误的方法就是给路由的endpoint参数指定视图函数名,即:
from flask import Flask, request, render_template, redirect, Markup, session
app = Flask(__name__)
app.secret_key = "abcdefghijklmn"
def wrapper(f):
def inner(*args, **kwargs):
if session.get("user"):
ret = f(*args, **kwargs)
return ret
else:
return redirect("/login")
return inner
@app.route("/login", methods=("GET","POST"))
def login():
if request.method == "GET":
return render_template("login.html")
if request.method == "POST":
username = request.form.get("username")
session["user"] = username
return "登陆成功"
@app.route("/home",endpoint="home", methods=("GET", "POST"))
@wrapper
def home():
return "这是home界面的内容"
@app.route("/index",endpoint="index")
@wrapper
def index():
return "我是index界面的内容"
app.run()
二、Flask中的路由参数
- @app.route()
@app.route(
"/<age>" // 动态路由参数,默认是string,也可以是"/<int:age>"
redirect_to = "/login" //不经过视图函数直接重定向指定url
defaults = {"age": 999} //指定默认参数
endpoint = "home" //路由别名,用于反向生成URL,即: url_for('名称')
methods = ("GET", "POST") //请求方式
strict_slashes = False //是否严格匹配url最后的"/",例:http://127.0.0.1:5000/home 和
//http://127.0.0.1:5000/home/
)
常用动态路由参数有以下五种,所有的路由系统都是基于以下对应关系来处理:
DEFAULT_CONVERTERS = {
'default': UnicodeConverter,
'string': UnicodeConverter,
'any': AnyConverter,
'path': PathConverter,
'int': IntegerConverter,
'float': FloatConverter,
'uuid': UUIDConverter,
}
url_for的用法
from flask import Flask,url_for
app = Flask(__name__)
@app.route("/index/<int:age>",endpoint="index")
def index(age):
url = url_for("index",age = age)
print(url) // "/index/122"
return "我是index界面的内容"
app.run()
- app.add_url_rule()方法:比@app.route()多了一个 view_func=view_func参数,其他的相同。
三、Flask配置文件
1. 初始化Flask实例时的配置
app = Flask(_name_,template_folder="template",static_folder="static",static_url_path="/static")
- static_url_path = "/static_folder" 访问静态目录文件时的地址 默认值是等于static_folder的名字,(应用场景描述:当后端static文件名修改后,加入前端页面使用了大量的之前的static路径,可以将static_url_path参数设置为老的,这样就可以不用修改前端代码了。)
- static_folder = "static" 静态文件的存放路径
- template_folder='templates' 模板路径
2. Flask实例的配置 app配置
- 方式一、app.config["DEBUG"] = True
PS: 由于Config对象本质上是字典,所以还可以使用app.config.update(...) - 方式二、app.config.from_object(obj)
class obj():
DEBUG = True
SECERT_KEY = "123123"
- 方式三、app.config.from_pyfile("settings.py")
settings.py
DEBUG = True
SECERT_KEY = "123123"
- 方式四、app.config.from_envvar("环境变量名称")
PS:环境变量的值为python文件名称名称,内部调用from_pyfile方法 - 方式五、app.config.from_json("json文件名称")
PS: JSON文件名称,必须是json格式,因为内部会执行json.loads - 方式六、app.config.from_mapping({'DEBUG':True})
PS:字典格式
四、Flask的蓝图
蓝图”和一个Flask应用对象很相似,但是并不是一个Flask应用对象。它是可以注册到Flask应用上的一系列操作(对于此的理解,后文会详细讲到)。使用“蓝图”,可以实现以下的一些功能:
- 将Flask应用“分割”为一系列“蓝图”的集合,简化了大型应用工作的方式;
- 在Flask应用上,以 URL 前缀和或子域名注册一个蓝图。可以以不同的URL多次注册一个蓝图;
- 通过蓝图提供模板过滤器、静态文件、模板和其它功能。
第一步:蓝图的创建(蓝图的示例和Flask的实例参数一样)
add.py
from flask import Blueprint,render_template
bp = Blueprint("bp", __name__,
template_folder="blueprint_temp",
static_folder="blueprint_static",
static_url_path="/static2")
@bp.route("/add")
def add():
return render_template("add.html")
第二步:注册蓝图:
from flask import Flask
import add
app = Flask(\__name__)
app.register_blueprint(add.bp)
if __name__ == '__main__':
app.run()
五、Flask里面的扩展,相当于django中的中间件
1.before_request 再请求进入视图函数之前作出处理 return None;before_request是顺序执行
2.after_request 在请求结束视图函数之后,返回客户端之前 ,要有参数和返回值,after_request是逆向执行
3.errorheadler(404) 自定制错误提示,自定义的函数必须有参数
- before_request和after_request装饰器的使用
from flask import Flask, request, render_template, redirect, Markup, session, url_for
app = Flask(__name__)
app.secret_key = "abcdefghijklmn"
@app.before_request
def process_request1():
print('process_request1')
@app.after_request
def process_response1(response): # 必须有参数
print('process_response1')
return response # 必须有返回值
@app.before_request
def process_request2():
print('process_request2')
@app.after_request
def process_response2(response): # 必须有参数
print('process_response2')
return response # 必须有返回值
@app.route("/login", methods=("GET", "POST"))
def login():
if request.method == "GET":
return render_template("login.html")
if request.method == "POST":
username = request.form.get("username")
session["user"] = username
return "登陆成功"
app.run()
访问login视图函数后的控制台输出结果为:
process_request1
process_request2
process_response2
process_response1
通过代码的打印结果可以看出,before_request顺序执行;after_request逆向执行
- errorhandler(404)的使用
@app.errorhandler(404)
def errors(code_or_exception): //必须有参数
return "错误" //可以返回字符串,html,重定向等
六、闪现:flash
session存在在服务端的一个字典里面,session保存起来,取一次里面还是有的,直到你删除之后才没有了。
flash的本质:flash是基于session创建的,flash支持往里边放值,只要你取一下就没有了,相当于pop了一下。不仅吧值取走,而且吧session里的东西去掉。
flash的使用:get_flashed_messages()和flash("内容")
from flask import Flask,session,render_template,request,flash,get_flashed_messages
import flask_config
app = Flask(__name__)
@app.route("/index")
def index():
res = get_flashed_messages()
if not res:
res = [""]
flash("你刚才访问了index")
return render_template("index.html",msg=res[0])
@app.route("/home")
def index1():
res = get_flashed_messages()
if not res:
res = [""]
flash("你刚才访问了home")
return render_template("index.html",msg=res[0])
if __name__ == '__main__':
app.run()
七、Flask的send_file使用
from flask import Flask,send_file
app = Flask(__name__)
@app.route("/index", endpoint="index")
def index():
return send_file(file_path) //send_file()的作用是打开文件传输内容
app.run()
八、Flask的jsonify的使用
- json.dumps的作用是序列化数据
- jsonify的作用是将后端数据json序列化,打包一个 content-Type:application/json 返回给客户端
from flask import Flask, jsonify
app = Flask(__name__)
@app.route("/index", endpoint="index")
def index():
#return json.dumps({123:"34"}) //传给前端的是json数据,仅此而已!
return jsonify({123:"34"})) //序列化数据,将响应头的content-Type: 更改为application/json
app.run()