一、路由系统
1. 示例
from flask import Flask,render_template,request,redirect,session,url_for app = Flask(__name__) # endpoint别名,通过别名可反向生成url # url后跟参数规则/index/<int:nid>,int需要指定,字符串可以直接使用<nid> # 参数数据类型示例 # @app.route('/user/<username>') # @app.route('/post/<int:post_id>') # @app.route('/post/<float:post_id>') # @app.route('/post/<path:path>') # @app.route('/login', methods=['GET', 'POST']) @app.route('/index/<int:nid>',methods=['GET',"POST"],endpoint='fff') def index(nid): v = url_for('fff',nid=123) # 结合endpoint,url_for反向生成url,可传参 print(v) # /index/123 return 'xxxx' if __name__ == '__main__': app.run()
2. @app.route和app.add_url_rule参数
rule URL规则 view_func, 视图函数名称 defaults=None, 默认值,在路由装饰器中为视图函数预设的实参,当URL中无参数,视图函数需要参数时,使用defaults={'k':'v'}为视图函数提供参数 endpoint=None, 名称,用于反向生成URL,即: url_for('名称') methods=None, 允许的请求方式,如:["GET","POST"] strict_slashes=None, 对URL最后的 / 符号是否严格要求, 如: @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>') 或 def func(adapter, nid): return "/home/888" @app.route('/index/<int:nid>', redirect_to=func) subdomain=None, 子域名访问,不加subdomain默认为www from flask import Flask, views, url_for app = Flask(import_name=__name__) app.config['SERVER_NAME'] = 'wupeiqi.com:5000' @app.route("/", subdomain="admin") def static_index(): """Flask supports static subdomains This is available at static.your-domain.tld""" return "static.your-domain.tld" @app.route("/dynamic", subdomain="<username>") # 动态接收子域名,并可传为参数 def username_index(username): """Dynamic subdomains are also supported Try going to user1.your-domain.tld/dynamic""" return username + ".your-domain.tld" if __name__ == '__main__': app.run()
3. flask扩展支持正则
from flask import Flask,url_for from werkzeug.routing import BaseConverter app = Flask(__name__) class RegexConverter(BaseConverter): """ flask中的url所有的数据类型得有自己的对应的类 DEFAULT_CONVERTERS = { 'default': UnicodeConverter, 'string': UnicodeConverter, 'any': AnyConverter, 'path': PathConverter, 'int': IntegerConverter, 'float': FloatConverter, 'uuid': UUIDConverter, } 自定义URL匹配正则表达式,RegexConverter类时之拥有正则可以匹配的类,进行匹配操作 """ def __init__(self, map, regex): super(RegexConverter, self).__init__(map) self.regex = regex def to_python(self, value): """ 路由匹配时,匹配成功后传递给视图函数中参数的值 :param value: :return: """ return int(value) def to_url(self, value): """ 使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数 :param value: :return: """ val = super(RegexConverter, self).to_url(value) return val app.url_map.converters['regex'] = RegexConverter # 将自定义正则匹配的类加入converters @app.route('/index/<regex("d+"):nid>',methods=['GET',"POST"],endpoint='fff') def index(nid): v = url_for('fff',nid=nid) print(v) # 输入:http://127.0.0.1:5000/index/888,输出/index/888 return 'xxx' if __name__ == '__main__': app.run()
二、Flask的FBV与CBV
1. FBV
# 方式一 @app.route('/index/<regex("d+"):nid>',methods=['GET',"POST"],endpoint='fff') def index(nid): v = url_for('fff',nid=nid) print(v) # 输入:http://127.0.0.1:5000/index/888,输出/index/888 return 'xxx' -------------------------------------------------------------------------------- # 方式二 def index(nid): v = url_for('fff',nid=nid) print(v) # 输入:http://127.0.0.1:5000/index/888,输出/index/888 return 'xxx' app.add_url_rule('/index',index)
2. CBV
from flask import Flask,views,url_for app = Flask(__name__) def auth(func): def wrapper(*args,**kwargs): print('before') result = func(*args,**kwargs) print('after') return result return wrapper class IndexView(views.MethodView): methods = ["GET"] # 相当于FBV中的@app.route('/index',methods=['GET','POST']) decorators = [auth,] # 所有的方法都经过这个装饰器 def get(self): v = url_for('fff') # 配合IndexView.as_view(name='fff')使用 print(v) return "GET" def post(self): return "POST" app.add_url_rule('/index',view_func=IndexView.as_view(name='fff'),) # name='index' 相当于FBV的endpoint使用,可反向生成url if __name__ == '__main__': app.run()
三、请求与相应
1. 请求及相应相关信息
# 请求相关信息 # request.method # request.args # request.form # request.values # request.cookies # request.headers # request.path # request.full_path # request.script_root # request.url # request.base_url # request.url_root # request.host_url # request.host # 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') # 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
2. 示例及urlencode,unquote,quote,jsonify,make_response的使用
from flask import Flask,url_for,request,jsonify,make_response from urllib.parse import urlencode,quote,unquote app = Flask(__name__) @app.route('/index',endpoint='xxx') def index(): # request # get_data = request.args # http://127.0.0.1:5000/index?nid=1&name=eiyouwei # print(get_data) # ImmutableMultiDict([('nid', '1'), ('name', 'eiyouwei')]) # # v = request.args.getlist('name') # http://127.0.0.1:5000/index?nid=1&name=eiyouwei # print(v) # ['eiyouwei'] # # 使用python模块urlencode,生成url参数 # get_data = request.args # http://127.0.0.1:5000/index?nid=1&name=eiyouwei # get_dict = get_data.to_dict() # 将参数信息转化为字典 # get_dict['gender'] = 'male' # url = urlencode(get_dict) # print(url) # nid=1&name=eiyouwei&gender=male # 针对中文在url参数中转化为的特殊字符的转化工具unquote,quote # val = request.query_string # http://127.0.0.1:5000/index?nid=1&name=%E5%93%8E%E5%91%80%E5%91%80 # print(val) # b'nid=1&name=%E5%93%8E%E5%91%80%E5%91%80' # print(unquote('%E5%93%8E%E5%91%80%E5%91%80')) # 哎呀呀 # print(quote('哎呀呀')) # %E5%93%8E%E5%91%80%E5%91%80 # response # return jsonify(name='alxe',age='180') # ''' # jsonify返回json格式的数据 # { # "age": "180", # "name": "alxe" # } # ''' response = make_response('xxx') # make_response可以响应头等加入信息,操作 response.headers['Olive'] = '111111' # 给响应头加入了信息Olive:111111 return response if __name__ == '__main__': app.run()
四、模板语言(jinjia2)
1. 视图函数
from flask import Flask,render_template,Markup app = Flask(__name__) def test(a1,a2): return a1 + a2 @app.template_global() # 无需传参,jinjia2全局可使用 def sb(a1, a2): return a1 + a2 @app.template_filter() # jinjia2简单操作即可使用 def db(a1, a2, a3): return a1 + a2 + a3 @app.route('/index',endpoint='xxx') def index(): v1 = '字符串' v2 = [11,22,33] v3 = {'k1':'v1','k2':'v2'} # v4 = "<input type='text'/>" v4 = Markup("<input type='text'/>") # 相当于django中的mark_safe,防止跨站XXS攻击 return render_template('index.html',v1=v1,v2=v2,v3=v3,v4=v4,test=test) if __name__ == '__main__': app.run()
2. 模板语言
{% extends 'layout.html' %} {%block body%} <p>{{v1}}</p> <ul> {% for item in v2 %} <li>{{item}}</li> {% endfor %} </ul> <ul> {% for k,v in v3.items() %} <!-- 与 django不同jinjia2需要加括号--> <li>{{k}} {{v}}</li> {% endfor %} </ul> <p>{{v3.k1}}</p> <p>{{v3.get('k1')}}</p> <!--<p>{{v4|safe}}</p>--> <p>{{v4}}</p> <p>{{test(1,23)}}</p> <p>{{sb(1,2)}}</p> <!--template_global可直接使用--> <p>{{1|db(2,3)}}</p> <!--template_filter需要用管道符调用,管道符之前是第一个参数,括号中是其余的参数--> <!--宏,想函数一样的使用--> {% macro abc(name, type='text', value='') %} <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> {% endmacro %} {{ abc('egon') }} {%endblock%}
3. layout
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>模板</h1> {%block body%}{%endblock%} </body> </html>
五、flask-session
1. session保存的原理
session本质上操作的是字典。以字典形式保存在内存当中。
flask默认方式,程序执行过程中,若干次操作session,首先保存在内存当中。
在最后返回的前,通过cookie保存在浏览器,提升了执行效率,节省了请求的此书。
其他框架可能会操作一次session,保存一次session到如数据库中。
2. session配置的方式
flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为: { 'PERMANENT_SESSION_LIFETIME': timedelta(days=31), # session超时时间 'SESSION_COOKIE_NAME': 'session', # session名称 'SESSION_COOKIE_DOMAIN': None, # session支持的域名 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True, 'SESSION_COOKIE_SECURE': False, 'SESSION_REFRESH_EACH_REQUEST': True, # 每次访问重新计算session失效时间 } from flask import Flask,session app = Flask(__name__) app.secret_key = 'adfadsfhjkhakljsdfh' app.config['SESSION_COOKIE_NAME'] = 'session_lvjing' @app.route('/index',endpoint='xxx') def index(): session['xxx'] = 123 return 'xxx' if __name__ == '__main__': app.run()
六、闪现(flash)
在session的基础上,把值放入session,取的同时将值删除(pop)。
如果普通的调用session保存传递,每次在session中都已存储了值,如果使用闪现则只会出现一次即消失。
from flask import Flask,session,flash,request,get_flashed_messages,redirect app = Flask(__name__) app.secret_key = 'adfadsfhjkhakljsdfh' @app.route('/index') def index(): msg = get_flashed_messages() # msg = session.get('msg','') print(msg) return 'xxx' @app.route('/login') def login(): flash('登录成功') # session['msg'] = 111 return redirect('/index') if __name__ == '__main__': app.run()
七、 仿中间件之扩展
扩展的默认执行顺序与django中的中间件一致,request根据先后顺序执行,response则相反,后进先出。
1 from flask import Flask 2 3 app = Flask(__name__) 4 5 app.secret_key = 'adfadsfhjkhakljsdfh' 6 7 8 # 在第一个用户访问时,执行之后不再执行, 9 # 原理为将一个变量置为False,第一次访问时改为True,之后再次访问不再执行 10 # @app.before_first_request 11 # def process_first_request(): 12 # print('process_first_request') 13 14 15 @app.before_request 16 def process_request1(): 17 print('process_request1') 18 19 @app.after_request 20 def process_response1(response): # 响应中间件需要提供response参数,及返回response参数 21 print('process_response1') 22 return response 23 24 @app.before_request 25 def process_request2(): 26 print('process_request2') 27 28 @app.after_request 29 def process_response2(response): # 响应中间件需要提供response参数,及返回response参数 30 print('process_response2') 31 return response 32 33 34 @app.route('/index') 35 def index(): 36 print('aaa') 37 return 'xxx' 38 39 40 if __name__ == '__main__': 41 app.run() 42 43 ------------------------------------ 44 45 process_request1 46 process_request2 47 aaa 48 process_response2 49 process_response1