一、路由系统
在入门中我们提到了flask框架中的两种路由形式,现在将以第一种形式,详细介绍其中的各个参数。具体参数如下:
#@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最后的 / 符号是否严格要求, ''' 如: 1、@app.route('/index', strict_slashes=False)访问:http: // www.xx.com / index / 或http: // www.xx.com / index均可 2、@app.route('/index', strict_slashes=True)仅访问http: // www.xx.com / index ''' redirect_to = None #重定向到指定地址 subdomain = None #子域名访问
1、带参数路径
常见五种路由如下,其中带参数的路由,需要指定参数的类型,不指定类型时即为默认的字符串类型
@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'])
如下实例,视图函数中的参数可以通过如下两种方式获得:一种就是我们说的如下形式的带参数的路径,另一种就是我们通过在路由中的default参数进行传值,这两种的形式的参数都可以在视图函数中进行获得和使用。
from flask import Flask app=Flask(__name__) @app.route("/index/<int:nid>",defaults={"cid":123}) def index(nid,cid): print(nid,cid) return "from index" if __name__ == '__main__': app.run()
2、url反向解析
在路由中的endpoint参数即为url的url别名,通过url别名,利用url_for()可以获得反向解析的路径,如下为但参数的反向解析实例,不带参数的路径在反向解析的时候不用给其参数即可。
from flask import Flask,url_for app=Flask(__name__) @app.route("/index/<int:nid>",endpoint="xxx") def index(nid): v=url_for("xxx",nid=nid) #带参数形式的反向解析 print(v) return "ok"
3、重定向参数
在我们的路由中,我们redirect_to这样一个参数,通过给其配置一个路径,则在请求当前路由的时候,不再访问当前路由所装饰的视图函数,而是访问重定向参数设置对应的路由下视图函数,实例如下:
from flask import Flask app=Flask(__name__) @app.route("/old",redirect_to="/new") #当访问/old路径时,会重定向到访问/new对应的视图 def old(): return "old" @app.route("/new") def new(): return "new"
4、子域名访问
(1)静态域名
在路由中,有这样的subdomain参数,通过它可以定义我们子域名访问限制,具体实例如下:
from flask import Flask app=Flask(__name__) app.config['SERVER_NAME'] = 'bjg.com:5000' #必须有这样的设置 @app.route("/index",subdomain="admin") def index(): return "index"
上例的的解释为:我们想要访问index视图函数,必须要通过admin.bjg.com:5000/index这个路径进行访问才可以访问到,即subdomain参数数限制了我们访问的域名。为了让我的上例测试成功,我们必须对admin.bjg.com域名进行解析,DNS解析一般会先从我们电脑上的文件中进行解析,如果解析不成功就会到公网上解析。为了测试,我们只需要在我们的电脑上进行上述域名的ip对应设置,让测试在电脑上完成。具体步骤如下:
1、找到路径C:WindowsSystem32driversetc 2、在此路径的hosts文件中设置: 127.0.01 admin.bjg.com
(2)动态域名
如上设置,我们会把域名限制死,不会很灵活,通过如下的参数的形式,只要能解析成功的域名我们都可以访问,如下:
from flask import Flask app=Flask(__name__) app.config['SERVER_NAME'] = 'bjg.com:5000' #必须有这样的设置 @app.route("/index",subdomain='<xxx>') def index(xxx): return "%s.bjg.com" %xxx ''' 假如有如下形式的域名解析关系,均可以成功访问index视图: sss.bjg.com 127.0.0.1 yyy.bjg.com 127.0.0.1 zzz.bjg.com 127.0.0.1 访问形式: sss.bjg.com :5000/index yyy.bjg.com :5000/index zzz.bjg.com :5000/index '''
5、自定义正则路由匹配
具体实现请参考如下实例:
from flask import Flask,url_for app = Flask(__name__) # 定义转换的类 from werkzeug.routing import BaseConverter class RegexConverter(BaseConverter): """ 自定义URL匹配正则表达式 """ 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 # 添加到converts中 app.url_map.converters['xxx'] = RegexConverter # 进行使用 @app.route('/index/<xxx("d+"):nid>',endpoint='xx') def index(nid): url_for('xx',nid=123) return "Index" if __name__ == '__main__': app.run()
二、视图函数
1、FBV形式
from flask import Flask,url_for app=Flask(__name__) # 方式二: @app.route("/index/") def index(): return "from index" #方式二: def demon(): return "from demon" app.add_url_rule("/demon",demon) if __name__ == '__main__': app.run()
2、CBV形式
如下实例,此种视图形式只能使用add_url_rule的形式匹配视图。
from flask import Flask,views,url_for app=Flask(__name__) def auth(func): def inner(*args,**kwargs): print("before") result=func(*args,**kwargs) print("after") return result return inner class IndexView(views.MethodView): #必须继承views.MethodView methods = ["POST"] #用于指定可以请求的方法,否则请求无法执行post视图 decorators = [auth,] #用于给视图加装饰器,通过列表加多个 def get(self): url_for("xxx") return "GET" def post(self): return "POST" app.add_url_rule('/index',view_func=IndexView.as_view(name="xxx")) #name='xxx'为设置的url别名 if __name__ == '__main__': app.run()
三、请求与响应
1、请求request
# 请求相关信息 # 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))
部分实例如下:
from flask import Flask,request,render_template,jsonify from urllib.parse import urlencode app=Flask(__name__) @app.route('/index',endpoint='xxx',methods=["POST","GET"]) def index(): if request.method=="POST": get_args=request.args print(get_args) #获得url中参数,如ImmutableMultiDict([('id', '1')]) get_dict=get_args.to_dict() print(get_dict) #将其转为字典:{'id': '1'} get_dict["xxx"]=18 url=urlencode(get_dict) print(url) #结果id=1&xxx=18 print(request.query_string) #结果:b'id=1' get_form = request.form print(get_form) #获得form表单中数据,如ImmutableMultiDict([('user', '321'), ('pswd', '321')]) get_values = request.values print(get_values) #获得即包含url数据又包含form表单中数据 return jsonify(name="alex",age=18) #返回json数据形式 return render_template("index.html") if __name__ == '__main__': app.run()
2、相应response
# 响应相关信息 # 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
四、模板语言
Flask使用的是Jinja2模板,所以其语法和Django无差别。具体使用见如下实例:
from flask import Flask,render_template,Markup app=Flask(__name__) #如下方式装饰的方法可以在全局的模板中使用 @app.template_global def sb(a,b): return a+b @app.template_filter def db(a,b,c): return a+b+c def test(a,b): return a+b @app.route('/index') def index(): v1=1111 v2=[11,22,33] v3={"a":1,"b":2} v4='<input type="text">' v5=Markup('<input type="text">') #Markup等价django的mark_safe return render_template("index.html",v1=v1,v2=v2,v3=v3,v4=v4,v5=v5,test=test) if __name__ == '__main__': app.run()
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <title>Title</title> </head> <body> <!--对象--> <h1>{{v1}}</h1> <!--列表循环--> {% for i in v2 %} <h2>{{i}}</h2> {% endfor %} <!--列表索引--> <h2>{{v2.0}} {{v2.1}} {{v2.2}}</h2> <!--字典循环--> <ul> {% for k,v in v3.items() %} <li>{{k}} {{v}}</li> {% endfor %} </ul> <!--字典索引--> <h2>{{v3.a}}</h2> <h2>{{v3.get("a")}}</h2> <!--标签--> <p>{{v4| safe}}</p> <p>{{v5}}</p> <!--函数--> <h1>{{test(23,10)}}</h1> <!--全局方法@app.template_global--> <p>{{sb(1,2)}}</p> <!--全局方法@app.template_filter--> <p> {{ 1|db(2,3)}}</p> </body> </html>
五、session
具体session的设置见如下实例:
from flask import Flask,session app = Flask(__name__) app.secret_key ='sdfsdfsdf' #设置session需要设置密钥 app.config['SESSION_COOKIE_NAME'] = 'session_lvning' #设置session相关参数 """ session相关参数: 'SESSION_COOKIE_NAME': 'session', 'SESSION_COOKIE_DOMAIN': None, 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True, 'SESSION_COOKIE_SECURE': False, 'SESSION_REFRESH_EACH_REQUEST': True, 'PERMANENT_SESSION_LIFETIME': timedelta(days=31) """ @app.route('/index',endpoint='xx') def index(): # session本质上操作的是字典,假设session保存在数据库 session['xx2'] = 123 session['xx3'] = 123 del session['xx2'] return "xxx" if __name__ == '__main__': # app.__call__ app.run()
六、闪现(flash)
是一个基于Session实现的用于保存数据的集合,其特点是:使用一次就删除。具体设置和使用实例说明如下:
from flask import Flask,flash,get_flashed_messages,redirect,url_for app=Flask(__name__) app.secret_key="adfsldgja" #flash基于session所以需要设置secret_key app.route('/user',endpoint="xxx") def user(): msg=get_flashed_messages() #取出数据后删除 print(msg) return "ok" @app.route('/add') def add(): flash("添加成功") #存入数据 return redirect('/user') if __name__ == '__main__': app.run()
七、扩展
有如下实例扩展,与django的中间件相似,可以用来处理例如登录验证:
from flask import Flask app=Flask(__name__) @app.before_request #无返回值 def request1(): print("from request1") @app.after_request #有返回值 def response1(response): print("from response1") return response @app.before_request def request2(): print("from request2") @app.after_request def response2(response): print("from response2") return response @app.route("/") def user(): print("main") return "ok" if __name__ == '__main__': app.run() ''' 请求/路径打印结果为: from request1 from request2 main from response2 from response1 '''