Flask框架:视图
1、视图中请求request
1.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))
测试代码:
1 from flask import Flask,request,Response 2 3 app = Flask(import_name=__name__) 4 5 @app.route('/index/') 6 def index(): 7 print("request.method:",request.method) 8 print("request.args:",request.args) 9 print("request.form:",request.form) 10 print("request.values:",request.values) 11 print("request.cookies:",request.cookies) 12 print("request.headers:",request.headers) 13 print("request.path:",request.path) 14 print("request.full_path:",request.full_path) 15 print("request.script_root:",request.script_root) 16 print("request.url:",request.url) 17 print("request.base_url:",request.base_url) 18 print("request.url_root:",request.url_root) 19 print("request.host_url:",request.host_url) 20 print("request.files:",request.files) 21 return Response("index") 22 23 if __name__ == '__main__': 24 app.run()
使用浏览器访问:http://127.0.0.1:5000/index/?a=1&b=2
执行结果:
request.method: GET request.args: ImmutableMultiDict([('a', '1'), ('b', '2')]) request.form: ImmutableMultiDict([]) request.values: CombinedMultiDict([ImmutableMultiDict([('a', '1'), ('b', '2')]), ImmutableMultiDict([])]) request.cookies: {'sessionid': 'o3fu279ez1lnsuoung8udxc95sxbglde', 'csrftoken': 'ISStt8sv8ATqEPt0MWfHiy6sqNSmz0GYB35Yam3SyAGcYBRzxnx4rsbr1XeNDF3I'} request.headers: Host: 127.0.0.1:5000 Connection: keep-alive Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cookie: sessionid=o3fu279ez1lnsuoung8udxc95sxbglde; csrftoken=ISStt8sv8ATqEPt0MWfHiy6sqNSmz0GYB35Yam3SyAGcYBRzxnx4rsbr1XeNDF3I request.path: /index/ request.full_path: /index/?a=1&b=2 request.script_root: request.url: http://127.0.0.1:5000/index/?a=1&b=2 request.base_url: http://127.0.0.1:5000/index/ request.url_root: http://127.0.0.1:5000/ request.host_url: http://127.0.0.1:5000/ request.files: ImmutableMultiDict([])
1.2、上传文件
获取文件对象:
obj = request.files['the_file_name']
获取安全的文件名:
secure_filename(f.filename)
保存文件:
obj.save('/var/www/uploads/' + secure_filename(f.filename))
上传文件源码:
1 import os 2 import uuid 3 from flask import Flask,request,Response,redirect,render_template,\ 4 url_for 5 from werkzeug.utils import secure_filename 6 7 UPLOAD_FOLDER = 'upload' 8 ALLOW_EXTENSIONS = set(['html','htm','doc','docx','mht','pdf','png','jpg']) 9 app = Flask(__name__) 10 app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER 11 12 #判断文件夹是否存在,如果不存在则创建 13 if not os.path.exists(UPLOAD_FOLDER): 14 os.makedirs(UPLOAD_FOLDER) 15 else: 16 pass 17 18 # 判断文件后缀是否在列表中 19 def allowed_file(filename): 20 return '.' in filename and \ 21 filename.rsplit('.', 1)[1] in ALLOW_EXTENSIONS 22 23 @app.route('/upload/', methods=['GET','POST']) 24 def upload_file(): 25 if request.method == "GET": 26 return render_template('index.html') 27 # 获取post过来的文件名称,从name=file参数中获取 28 file = request.files['file'] 29 if file and allowed_file(file.filename): 30 # secure_filename方法会去掉文件名中的中文 31 filename = secure_filename(file.filename) 32 # 因为上次的文件可能有重名,因此使用uuid保存文件 33 file_name = str(uuid.uuid4()) + '.' + filename.rsplit('.', 1)[1] 34 file_path = os.path.join(app.config['UPLOAD_FOLDER'], file_name) 35 file.save(file_path) 36 return redirect(url_for('upload_file', filename=filename)) 37 return Response("上传文件格式不支持,只支持:'html','htm','doc','docx','mht','pdf','png','jpg'") 38 39 if __name__ == '__main__': 40 app.run()
前端index.html源码:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 9 <form action="" method="post" enctype="multipart/form-data"> 10 <input type="file" name="file"> 11 <input type="submit"> 12 </form> 13 </body> 14 </html>
2、响应
几种响应体:
return “asdf” return jsonify({'k1':'v1'}) return render_template('xxx.html') return redirect('/index/')
定制响应头:
obj = make_response("asdf") obj.headers['xxxxxxx'] = '123' obj.set_cookie('key', 'value') return obj
3、模板语言
源码:
后端代码:
1 from flask import Flask,render_template,request,redirect,session,url_for,jsonify,make_response,Markup,flash,get_flashed_messages 2 3 app = Flask(__name__) 4 5 app.config.from_object("settings.DevelopmentConfig") 6 7 STUDENT_DICT = { 8 1:{'name':'王龙泰','age':38,'gender':'中'}, 9 2:{'name':'小东北','age':73,'gender':'男'}, 10 3:{'name':'田硕','age':84,'gender':'男'}, 11 } 12 13 14 @app.template_global() 15 def sb(a1, a2): 16 # {{sb(1,9)}} 17 return a1 + a2 18 19 @app.template_filter() 20 def db(a1, a2, a3): 21 # {{ 1|db(2,3) }} 22 return a1 + a2 + a3 23 24 25 @app.route('/login',methods=["GET","POST"]) 26 def login(): 27 print('login') 28 if request.method == 'GET': 29 return render_template('login.html') 30 user = request.form.get('user') 31 pwd = request.form.get('pwd') 32 if user == 'oldboy' and pwd == '666': 33 session['user'] = user 34 return redirect('/index') 35 return render_template('login.html',error='用户名或密码错误') 36 37 38 @app.route('/index') 39 def index(): 40 print('index') 41 return render_template('index.html',stu_dic=STUDENT_DICT) 42 43 @app.route('/delete/<int:nid>') 44 def delete(nid): 45 46 del STUDENT_DICT[nid] 47 return redirect(url_for('index')) 48 49 @app.route('/detail/<int:nid>') 50 def detail(nid): 51 info = STUDENT_DICT[nid] 52 return render_template('detail.html',info=info) 53 54 def func(arg): 55 return arg + 1 56 57 @app.route('/tpl') 58 def tpl(): 59 context = { 60 'users':['longtai','liusong','zhoahuhu'], 61 'txt':Markup("<input type='text' />"), 62 'func':func 63 } 64 65 return render_template('tpl.html',**context) 66 67 if __name__ == '__main__': 68 app.run()
1 from datetime import timedelta 2 class Config(object): 3 DEBUG = False 4 TESTING = False 5 SECRET_KEY = "asdfasdfas23" 6 DATABASE_URI = 'sqlite://:memory:' 7 8 SESSION_COOKIE_NAME = 'session' 9 SESSION_COOKIE_DOMAIN = None 10 SESSION_COOKIE_PATH = None 11 SESSION_COOKIE_HTTPONLY = True 12 SESSION_COOKIE_SECURE = False 13 SESSION_REFRESH_EACH_REQUEST = True 14 PERMANENT_SESSION_LIFETIME = timedelta(hours=1) 15 16 17 class ProductionConfig(Config): 18 DATABASE_URI = 'mysql://user@localhost/foo' 19 20 21 class DevelopmentConfig(Config): 22 DEBUG = True 23 24 25 class TestingConfig(Config): 26 TESTING = True
前端HTML:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h1>模板</h1> {% block content %}{% endblock %} </body> </html>
{% extends "layout.html"%} {% block content %} {{users.0}} {{users[0]}} {{txt}} <!--{{txt|safe}}--> {{func(6)}} {{sb(1,9)}} {{ 1|db(2,3) }} {% if 1|db(2,3) %} <div>666</div> {% else %} <div>999</div> {% endif %} {% include "form.html" %} {% macro ccccc(name, type='text', value='') %} <h1>宏</h1> <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> <input type="submit" value="提交"> {% endmacro %} {{ ccccc('n1') }} {{ ccccc('n2') }} {% endblock %}
4、session
当请求刚到来:flask读取cookie中session对应的值:eyJrMiI6NDU2LCJ1c2VyIjoib2xkYm95,将该值解密并反序列化成字典,放入内存以便视图函数使用。
from flask import Flask,render_template,request,redirect,session,url_for,jsonify,make_response,Markup,flash,get_flashed_messages app = Flask(__name__) app.config.from_object("settings.DevelopmentConfig") STUDENT_DICT = { 1:{'name':'王龙泰','age':38,'gender':'中'}, 2:{'name':'小东北','age':73,'gender':'男'}, 3:{'name':'田硕','age':84,'gender':'男'}, } @app.before_request def xxxxxx(): if request.path == '/login': return None if session.get('user'): return None return redirect('/login') @app.route('/login',methods=["GET","POST"]) def login(): print('login') if request.method == 'GET': return render_template('login.html') user = request.form.get('user') pwd = request.form.get('pwd') if user == 'oldboy' and pwd == '666': session['user'] = user return redirect('/index') return render_template('login.html',error='用户名或密码错误') @app.route('/index') def index(): print('index') return render_template('index.html',stu_dic=STUDENT_DICT) @app.route('/delete/<int:nid>') def delete(nid): del STUDENT_DICT[nid] return redirect(url_for('index')) @app.route('/detail/<int:nid>') def detail(nid): info = STUDENT_DICT[nid] return render_template('detail.html',info=info) if __name__ == '__main__': app.run()
当请求结束时,flask会读取内存中字典的值,进行序列化+加密,写入到用户cookie中。
5、闪现flash
原理:在session中存储一个数据,读取时通过pop将数据移除。
1 from flask import Flask,flash,get_flashed_messages 2 3 app = Flask(__name__) 4 app.secret_key = "123213132" 5 6 @app.route('/page1') 7 def page1(): 8 9 flash('临时数据存储','error') 10 flash('sdfsdf234234','error') 11 flash('adasdfasdf','info') 12 13 return "Session" 14 15 @app.route('/page2') 16 def page2(): 17 print(get_flashed_messages(category_filter=['error'])) 18 return "Session" 19 20 21 if __name__ == '__main__': 22 app.run()
6、中间件
app.run()执行Flask类的run方法,该方法调用werkzeug.serving的run_simple方法:
from werkzeug.serving import run_simple try: run_simple(host, port, self, **options) finally: # reset the first request information if the development server # reset normally. This makes it possible to restart the server # without reloader and that stuff from an interactive shell. self._got_first_request = False
其中self即是Flask类实例化的对象app。
用户请求到来后会执行self方法,即app()。app()会调用app对象的__call__方法。
def __call__(self, environ, start_response): """The WSGI server calls the Flask application object as the WSGI application. This calls :meth:`wsgi_app` which can be wrapped to applying middleware.""" return self.wsgi_app(environ, start_response)
__call__方法中调用app对象的wsgi_app方法。
因此如果要实现中间件功能,就必须在wsgi_app方法执行前后添加功能。即在wsgi_app的__call__方法中添加请求处理前功能和请求处理后功能。
1 from flask import Flask 2 3 app = Flask(__name__) 4 5 @app.route('/index') 6 def index(): 7 print('index') 8 return "Index" 9 10 class Middleware(object): 11 def __init__(self,old): 12 self.old = old 13 14 def __call__(self, *args, **kwargs): 15 print("前") 16 ret = self.old(*args, **kwargs) 17 print("后") 18 return ret 19 20 if __name__ == '__main__': 21 app.wsgi_app = Middleware(app.wsgi_app) 22 app.run()
7、特殊装饰器
before_request:请求处理前执行
after_request:请求处理完后执行
before_first_request:第一次请求处理前执行
template_global:模板中使用
template_filter:模板中用于过滤
errorhandler:请求发生错误时执行
1 from flask import Flask 2 app = Flask(__name__) 3 4 @app.before_first_request 5 def x1(): 6 print('123123') 7 8 @app.route('/index') 9 def index(): 10 print('index') 11 return "Index" 12 13 @app.route('/order') 14 def order(): 15 print('order') 16 return "order" 17 18 @app.errorhandler(404) 19 def not_found(arg): 20 print(arg) 21 return "没找到" 22 23 if __name__ == '__main__': 24 app.run()
8、CBV
1 import functools 2 from flask import Flask,views,Response 3 4 app = Flask(__name__) 5 6 def wrapper(func): 7 @functools.wraps(func) 8 def inner(*args,**kwargs): 9 return func(*args,**kwargs) 10 return inner 11 12 class UserView(views.MethodView): 13 methods = ['GET','POST'] 14 decorators = [wrapper,] 15 16 def get(self,*args,**kwargs): 17 return 'GET' 18 19 def post(self,*args,**kwargs): 20 return 'POST' 21 22 app.add_url_rule('/user',None,UserView.as_view('uuuu')) 23 24 if __name__ == '__main__': 25 app.run()
9、蓝图Blueprint
项目目录:
crm:
crm:
static
templates:
login.html
views:
account.py
user.py
__init__.py
manage.py
1 <!DOCTYPE html> 2 <html lang="zh-CN"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <meta name="viewport" content="width=device-width, initial-scale=1"> 7 </head> 8 <body> 9 <h1>用户登录</h1> 10 </body> 11 </html>
1 from flask import Blueprint,render_template 2 3 ac = Blueprint('ac',__name__) 4 5 @ac.before_request 6 def x1(): 7 print('app.before_request') 8 9 @ac.route('/login') 10 def login(): 11 return render_template('login.html') 12 13 @ac.route('/logout') 14 def logout(): 15 return 'Logout'
1 from flask import Blueprint 2 3 uc = Blueprint('uc',__name__) 4 5 @uc.route('/list') 6 def list(): 7 return 'List' 8 9 @uc.route('/detail') 10 def detail(): 11 return 'detail'
1 from flask import Flask 2 from .views.account import ac 3 from .views.user import uc 4 5 def create_app(): 6 7 app = Flask(__name__) 8 9 # @app.before_request 10 # def x1(): 11 # print('app.before_request') 12 app.register_blueprint(ac) 13 app.register_blueprint(uc,url_prefix='/api') 14 return app
1 from crm import create_app 2 3 app = create_app() 4 5 if __name__ == '__main__': 6 app.run()