一.flask是什么?
Flask是一个使用 Python 编写的轻量级 Web 应用框架。其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2 。
因为它使用简单的核心,用 extension 增加其他功能。Flask没有默认使用的数据库、窗体验证工具。
二.知识点
1.实例化flask对象
app = Flask(__name__,template_folder='templates',static_url_path='/static')
2.添加路由的方式
方式一: @app.route('/login') def index(): return render_template('login.html') 方式二: def login(): return render_template('login.html') app.add_url_rule('/login', "n1", login) #'n1'为别名
3.添加路由关系
将url和视图函数封装成一个Rule对象)添加到Flask的url_map字段中(详见)
4.flask+自定义装饰器(简单登录验证)
1 from flask import Flask,render_template,request,redirect,session 2 app = Flask(__name__,template_folder='templates',static_url_path='/static') 3 app.secret_key = "asdfafsd" #加盐作用,必须有值 4 5 @app.route('/login',methods=['GET','POST']) 6 def login(): 7 if request.method == 'GET': 8 return render_template('login.html') 9 else: 10 user = request.form.get('user') 11 pwd = request.form.get('pwd') 12 if user == '张良' and pwd == '123': 13 session['user_info'] = user 14 return redirect('/index') 15 else: 16 return render_template('login.html',msg='用户名或者密码错误!') 17 18 def deco(func): 19 def _deco(*args,**kwargs): 20 if not session.get('user_info'): 21 return redirect('/login') 22 return func(*args, **kwargs) 23 return _deco 24 25 @app.route('/index',methods=['GET']) 26 @deco #调用装饰器函数写在路由下面 27 def index(): 28 return render_template('index.html') 29 30 if __name__ == '__main__': 31 app.run() 32 33 login.html 34 <body> 35 <form method="post"> 36 <p>用户名<input type="text" name="user"></p> 37 <p>密 码<input type="text" name="pwd"></p> 38 <input type="submit">{{ msg }} 39 </form> 40 </body>
5.请求响应相关
1 request.form #POST请求,获取表单内容 2 request.args #GET请求,字典形式的,获取url中传过来的键值对 3 request.querystring #GET请求,bytes形式的 4 request.url #返回当前请求完整的URL 5 request.base_url #不带参数的URL 6 request.path #url中的路径部分
from urllib.parse import urlencode,quote,unquote,make_response get_data = request.args #ImmutableMultiDict([''id':'1','name':'tom']) get_dict = get_data.to_dict #{''id':'1','name':'tom'} get_dict['xx] = 18 url = urlencode(get_dict) #id=1&name=tom&xx=18 request.files obj = request.files['the_file_name'] obj.save('/var/www/uploads/' + secure_filename(f.filename)) #请求文件中的url中如果有中文,会得到: val = "%E6%8A%8A%E5%87%A0%E4%B8%AA" 解码: unquote(val) #返回更多的内容 response = make_response("xxxx") response.header['xxx'] = ‘123’ return response
5.路由系统
@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_CONVERTERS = { 'default': UnicodeConverter, 'string': UnicodeConverter, 'any': AnyConverter, 'path': PathConverter, 'int': IntegerConverter, 'float': FloatConverter, 'uuid': UUIDConverter, }
@app.route和app.add_url_rule参数:
1 rule, URL规则 2 view_func, 视图函数名称 3 defaults=None, 默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数 4 endpoint=None, 名称,用于反向生成URL,即: url_for('名称') 5 methods=None, 允许的请求方式,如:["GET","POST"] 6 7 8 strict_slashes=None, 对URL最后的 / 符号是否严格要求, 9 如: 10 @app.route('/index',strict_slashes=False), 11 访问 http://www.xx.com/index/ 或 http://www.xx.com/index均可 12 @app.route('/index',strict_slashes=True) 13 仅访问 http://www.xx.com/index 14 redirect_to=None, 重定向到指定地址 15 如: 16 @app.route('/index/<int:nid>', redirect_to='/home/<nid>') 17 或 18 def func(adapter, nid): 19 return "/home/888" 20 @app.route('/index/<int:nid>', redirect_to=func) 21 subdomain=None, 子域名访问 22 from flask import Flask, views, url_for 23 24 app = Flask(import_name=__name__) 25 app.config['SERVER_NAME'] = 'wupeiqi.com:5000' 26 27 28 @app.route("/", subdomain="admin") 29 def static_index(): 30 """Flask supports static subdomains 31 This is available at static.your-domain.tld""" 32 return "static.your-domain.tld" 33 34 35 @app.route("/dynamic", subdomain="<username>") 36 def username_index(username): 37 """Dynamic subdomains are also supported 38 Try going to user1.your-domain.tld/dynamic""" 39 return username + ".your-domain.tld" 40 41 42 if __name__ == '__main__': 43 app.run()
URL反向解析
from flask import Flask, url_for def index(): v = url_for("xxx") print(v) return "index" @app.route('/zzz/<int:nid>',endpoint="aaa") #endpoint是别名 def zzz(nid): v = url_for("aaa",nid=nid) print(v) return "index2"
redirect_to:直接重定向,原url有参数时,跳转时也要传参,注意:不用加类型
6.自定制正则路由匹配
1 from flask import Flask, views, url_for 2 from werkzeug.routing import BaseConverter 3 4 app = Flask(import_name=__name__) 5 6 7 class RegexConverter(BaseConverter): 8 """ 9 自定义URL匹配正则表达式 10 """ 11 def __init__(self, map, regex): 12 super(RegexConverter, self).__init__(map) 13 self.regex = regex 14 15 def to_python(self, value): 16 """ 17 路由匹配时,匹配成功后传递给视图函数中参数的值 18 :param value: 19 :return: 20 """ 21 return int(value) 22 23 def to_url(self, value): 24 """ 25 使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数 26 :param value: 27 :return: 28 """ 29 val = super(RegexConverter, self).to_url(value) 30 return val 31 32 # 添加到flask中 33 app.url_map.converters['regex'] = RegexConverter 34 35 36 @app.route('/index/<regex("d+"):nid>') 37 def index(nid): 38 print(url_for('index', nid='888')) 39 return 'Index' 40 41 42 if __name__ == '__main__': 43 app.run() 44 45 #自定制正则路由匹配
7.模板使用
和Django使用类似......
不同之处:
前端循环字典时,dict.items(),后面的括号需要加;后端传来一个字典,前端可用get.('xxx')取值
markup:相当于Django的mark_safe;
template_global() template_filter() (在所有的页面都可以使用)
1 @app.template_global() 2 def dd(a1, a2): 3 return a1 + a2 4 @app.template_filter() 5 def pp(a1, a2, a3): 6 return a1 + a2 + a3 7 8 调用:{{dd(1,2)}} {{ 1|pp(2,3)}}(用‘|’区分)
宏:只有定义的东西在很多地方去使用的时候才去用它
1 {% macro input(name, type='text', value=' ') %} 2 <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> 3 {% endmacro %} 4 5 {{ input('n1') }}
8.session
-
设置:session['username'] = 'xxx'
- 删除:session.pop('username', None)
1 from flask import Flask, session, redirect, url_for, escape, request 2 3 app = Flask(__name__) 4 5 @app.route('/') 6 def index(): 7 if 'username' in session: 8 return 'Logged in as %s' % escape(session['username']) 9 return 'You are not logged in' 10 11 @app.route('/login', methods=['GET', 'POST']) 12 def login(): 13 if request.method == 'POST': 14 session['username'] = request.form['username'] 15 return redirect(url_for('index')) 16 return ''' 17 <form action="" method="post"> 18 <p><input type=text name=username> 19 <p><input type=submit value=Login> 20 </form> 21 ''' 22 23 @app.route('/logout') 24 def logout(): 25 # remove the username from the session if it's there 26 session.pop('username', None) 27 return redirect(url_for('index')) 28 29 # set the secret key. keep this really secret: 30 app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT' 31 32 基本使用
pip3 install Flask-Session run.py from flask import Flask from flask import session from pro_flask.utils.session import MySessionInterface app = Flask(__name__) app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT' app.session_interface = MySessionInterface() @app.route('/login.html', methods=['GET', "POST"]) def login(): print(session) session['user1'] = 'alex' session['user2'] = 'alex' del session['user2'] return "内容" if __name__ == '__main__': app.run() session.py #!/usr/bin/env python # -*- coding:utf-8 -*- import uuid import json from flask.sessions import SessionInterface from flask.sessions import SessionMixin from itsdangerous import Signer, BadSignature, want_bytes class MySession(dict, SessionMixin): def __init__(self, initial=None, sid=None): self.sid = sid self.initial = initial super(MySession, self).__init__(initial or ()) def __setitem__(self, key, value): super(MySession, self).__setitem__(key, value) def __getitem__(self, item): return super(MySession, self).__getitem__(item) def __delitem__(self, key): super(MySession, self).__delitem__(key) class MySessionInterface(SessionInterface): session_class = MySession container = {} def __init__(self): import redis self.redis = redis.Redis() def _generate_sid(self): return str(uuid.uuid4()) def _get_signer(self, app): if not app.secret_key: return None return Signer(app.secret_key, salt='flask-session', key_derivation='hmac') def open_session(self, app, request): """ 程序刚启动时执行,需要返回一个session对象 """ sid = request.cookies.get(app.session_cookie_name) if not sid: sid = self._generate_sid() return self.session_class(sid=sid) signer = self._get_signer(app) try: sid_as_bytes = signer.unsign(sid) sid = sid_as_bytes.decode() except BadSignature: sid = self._generate_sid() return self.session_class(sid=sid) # session保存在redis中 # val = self.redis.get(sid) # session保存在内存中 val = self.container.get(sid) if val is not None: try: data = json.loads(val) return self.session_class(data, sid=sid) except: return self.session_class(sid=sid) return self.session_class(sid=sid) def save_session(self, app, session, response): """ 程序结束前执行,可以保存session中所有的值 如: 保存到resit 写入到用户cookie """ domain = self.get_cookie_domain(app) path = self.get_cookie_path(app) httponly = self.get_cookie_httponly(app) secure = self.get_cookie_secure(app) expires = self.get_expiration_time(app, session) val = json.dumps(dict(session)) # session保存在redis中 # self.redis.setex(name=session.sid, value=val, time=app.permanent_session_lifetime) # session保存在内存中 self.container.setdefault(session.sid, val) session_id = self._get_signer(app).sign(want_bytes(session.sid)) response.set_cookie(app.session_cookie_name, session_id, expires=expires, httponly=httponly, domain=domain, path=path, secure=secure) 自定义Session
#!/usr/bin/env python # -*- coding:utf-8 -*- """ pip3 install redis pip3 install flask-session """ from flask import Flask, session, redirect from flask.ext.session import Session app = Flask(__name__) app.debug = True app.secret_key = 'asdfasdfasd' app.config['SESSION_TYPE'] = 'redis' from redis import Redis app.config['SESSION_REDIS'] = Redis(host='192.168.0.94',port='6379') Session(app) @app.route('/login') def login(): session['username'] = 'alex' return redirect('/index') @app.route('/index') def index(): name = session['username'] return name if __name__ == '__main__': app.run() 第三方session
session配置参数
- session超时时间如何设置? app.config['SESSION_COOKIE_NAME'] = 'session_lvning' 跟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)
9.闪现
本质:flash是基于session创建的,flash支持往里边放值,只要你取一下就没有了,相当于pop了一下。
1 from flask import Flask, flash, redirect, render_template, request, get_flashed_messages 2 app = Flask(__name__) 3 app.secret_key = 'some_secret' 4 flag = True 5 @app.route('/index') 6 def index1(): 7 global flag 8 if flag: 9 flash('登录成功!') 10 flag=False 11 return render_template('index.html') 12 13 if __name__ == "__main__": 14 app.run(port=8600) 15 16 #index.html 17 <!DOCTYPE html> 18 <html lang="en"> 19 <head> 20 <meta charset="UTF-8"> 21 <title>Title</title> 22 </head> 23 <body> 24 {% for msg in get_flashed_messages() %} 25 <p>{{ msg }}</p> 26 {% endfor %} 27 </body> 28 </html>
10.flask中通过内置函数实现中间价的效果
from flask import Flask,session,Session,flash,get_flashed_messages,redirect,render_template,request
app = Flask(__name__)
app.secret_key ='sdfsdfsdf'
@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.before_first_request:当程序运行起来,第一个请求来的时候就只执行一次,下次再来就不会在执行了
11.flask中的CBV模式和FBV模式
1 def auth(func): 2 def inner(*args, **kwargs): 3 result = func(*args, **kwargs) 4 return result 5 return inner 6 7 class IndexView(views.MethodView): 8 # methods = ['POST'] #只允许POST请求访问 9 decorators = [auth,] #如果想给所有的get,post请求加装饰器,就可以这样来写 10 11 def get(self): #如果是get请求需要执行的代码 12 v = url_for('index') 13 print(v) 14 return "GET" 15 16 def post(self): #如果是post请求执行的代码 17 return "POST" 18 19 app.add_url_rule('/index', view_func=IndexView.as_view(name='index')) #name指定的是别名,会当做endpoint使用 20 21 if __name__ == '__main__': 22 app.run()
1 方式一: 2 @app.route('/index',endpoint='xx') 3 def index(nid): 4 url_for('xx',nid=123) 5 return "Index" 6 7 方式二: 8 def index(nid): 9 url_for('xx',nid=123) 10 return "Index" 11 12 app.add_url_rule('/index',index)