Flask 基于 Python开发 ,依赖 jinjia2模板 和 Werkzeug WSGI服务 的一个微型框架。
Werkzeug本质是Socket服务端,用于 接收http请求 并对请求进行预处理,然后触发Flask框架。
开发人员 基于 Flask框架提供的功能 对请求进行相应处理,并返回给用户。
Flask的特点是“微小”(micro),保持核心简单而易于扩展。Flask 支持用扩展来给应用添加功能。如:数据库集成,表单验证,用户认证等。
# 安装 pip3 install flask
from werkzeug.wrappers import Request, Response @Request.application def hello(request): return Response('Hello World!') if __name__ == '__main__': from werkzeug.serving import run_simple run_simple('localhost', 4000, hello)
基本使用
from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello World!' if __name__ == '__main__': app.run()
Flask 提供的功能
一、配置文件
flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:
{ 'DEBUG': get_debug_flag(default=False), 是否开启Debug模式 'TESTING': False, 是否开启测试模式 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': None, 'PERMANENT_SESSION_LIFETIME': timedelta(days=31), 'USE_X_SENDFILE': False, 'LOGGER_NAME': None, 'LOGGER_HANDLER_POLICY': 'always', 'SERVER_NAME': None, 'APPLICATION_ROOT': None, '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, 'MAX_CONTENT_LENGTH': None, 'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12), 'TRAP_BAD_REQUEST_ERRORS': False, 'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', 'JSON_AS_ASCII': True, 'JSON_SORT_KEYS': True, 'JSONIFY_PRETTYPRINT_REGULAR': True, 'JSONIFY_MIMETYPE': 'application/json', 'TEMPLATES_AUTO_RELOAD': None, }
配置方法
方式一: app.config['DEBUG'] = True PS: 由于Config对象本质上是字典,所以还可以使用app.config.update(...) 方式二: # app.config.from_object("python类或类的路径") PS: 从sys.path中已经存在路径开始写 app.config.from_object("settings.DevelopmentConfig") settings.py class Config(object): DEBUG = False TESTING = False DATABASE_URI = 'sqlite://:memory:' class ProductionConfig(Config): DATABASE_URI = 'mysql://user@localhost/foo' class DevelopmentConfig(Config): DEBUG = True class TestingConfig(Config): TESTING = True PS: settings.py文件默认路径要放在程序root_path目录,如果instance_relative_config为True,则就是instance_path目录
settings.py class Foo: DEBUG = True TEST = True xx.py import importlib path = "settings.Foo" p,c = path.rsplit('.',maxsplit=1) m = importlib.import_module(p) cls = getattr(m,c) # 如果找到这个类? for key in dir(cls): if key.isupper(): print(key,getattr(cls,key)) # 获取路径,根据字符串导入模块,反射得到类, 获取类中大写的变量和值。
二、路由
- <nid> 默认为字符串,还有int,path,any,float,uuid。 - methods默认只有GET - endpoint 用来反向生成URL,如果没有设置,则默认函数名 - url_for('endpoint') / url_for("index",nid=777) # /index/77 - 动态路由: @app.route('/index/<int:nid>',methods=['GET','POST'],endpoint='n1') def index(nid): print(nid) print(url_for('n1')) return "Index"
三、视图
四、请求相关
django中的request是参数,而flask中的request是导入的。
from flask import 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 importrender_template,redirect,jsonify,make_response 响应体: return “字符串” return jsonify({'k1':'v1'}) return render_template('xxx.html',**{}) return redirect() 定制响应头: obj = make_response("asdf") # obj是flask.wrappers.Response类型 obj.headers['xxxxxxx'] = '123' obj.set_cookie('key', 'value') obj.delete_cookie('key') return obj
六、session
session需要从flask导入,使用时加密后存储在用户浏览器的cookies。
使用session,要设置 app.secret_key.
from Flask import session
设置:session['username'] = 'xxx' 删除:session.pop('username', None) del session['username'] 当请求刚到来:flask读取cookie中session对应的值:eyJrMiI6NDU2LCJ1c2VyIjoib2xkYm95,将该值解密并反序列化成字典,放入内存以便视图函数使用。 视图函数: @app.route('/ses') def ses(): session['k1'] = 123 session['k2'] = 456 del session['k1'] return "Session" 当请求结束时,flask会读取内存中字典的值,进行序列化+加密,写入到用户cookie中。
练习:利用上面的flask知识做一个简单的用户认证功能。
示例程序:学生管理 版本一: @app.route('/index') def index(): if not session.get('user'): return redirect(url_for('login')) return render_template('index.html',stu_dic=STUDENT_DICT) 版本二: 在需要认证功能的视图前添加@auth import functools def auth(func): @functools.wraps(func) def inner(*args,**kwargs): if not session.get('user'): return redirect(url_for('login')) ret = func(*args,**kwargs) return ret return inner @app.route('/index') @auth def index(): return render_template('index.html',stu_dic=STUDENT_DICT) 应用场景:比较少的函数中需要额外添加功能。 版本三:before_request 只有写一次就在每一个视图前添加认证功能 @app.before_request def xxxxxx(): if request.path == '/login': return None if session.get('user'): return None return redirect('/login')
七、模板渲染(jinjia2)
Flask使用的是Jinja2模板,所以其语法和Django几乎无差别。
区别一:传入函数时,django自动执行,flask要加()才执行。
1 u = "<input type='text' />" 2 3 前端:{{ u|safe }} 4 5 后端:from Flask import MarkUp 6 7 MarkUp(u) # 和django的mark_safe 等价
1 {% macro c1(name,type="text",value=' ') %} 2 3 <h1>宏</h1> 4 <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> 5 <input type="submit" value="提交"> 6 7 {% endmacro %} 8 9 {{% c1(" n1") %}} 10 11 {{% c2 (" n2") %}}
1 base.html 2 <!DOCTYPE html> 3 <html lang="zh-CN"> 4 <head> 5 <meta charset="UTF-8"> 6 <title>Title</title> 7 <meta name="viewport" content="width=device-width, initial-scale=1"> 8 </head> 9 <body> 10 <h1>模板</h1> 11 12 {% block content %}{% endblock %} 13 14 </body> 15 </html> 16 17 tpl.html 18 {% extends "base.html"%} 19 20 21 {% block content %} 22 {{users.0}} 23 24 25 {% endblock %}
1 xxx.html 2 {% include "form.html" %} 3 4 form.html 5 <form> 6 <input type="text"> 7 </form>
1 后端: 2 @app.template_global() 3 def sb(a1, a2): 4 return a1 + a2 5 6 @app.template_filter() 7 def db(a1, a2, a3): 8 9 return a1 + a2 + a3 10 11 前端: 12 {{sb(1,9)}} 13 14 {{ 1|db(2,3) }}
区别二 :flask可以 {% if 1|db(2,3) %}可以做判断 在模板里做计算
区别三:django没有宏
区别四:可以执行python语法,如:dict.get() list['xx']
区别五:后端: MarkUp("asdf")
1 {% for k,v in stu_dic.items() %} 2 # 像python语法一样,要加()遍历k或v 3 # for k in stu_dic / for k in stu_dic.keys()/ for k in stu.values() 4 <tr> 5 <td>{{k}}</td> 6 <td>{{v.name }}</td> 7 <td>{{v[age]}}</td> 8 <td>{{v.gender}}</td> 9 <td> 10 <a href="/detail/{{k}}">查看详细</a> 11 | 12 <a href="/delete/{{k}}">删除</a> 13 14 </td> 15 </tr> 16 {% endfor %} 17 18 stu_dic={ 19 1 :{name:"alex",age:"18",gender:"男"}, 20 。。。。。。 21 }
八、闪现flash
在session中存储一个数据,读取时通过pop将数据移除。
from flask import Flask,flash,get_flashed_messages # print(session['uuuuu']) # del session['uuuuu'] # session.pop('uuuuu') @app.route('/page1') def page1(): flash('临时数据存储','error') flash('sdfsdf234234','error') flash('adasdfasdf','info') return "Session" @app.route('/page2') def page2(): print(get_flashed_messages(category_filter=['error'])) return "Session" {{% for message in get_flashed_messages() %}}
九、中间件
原理:类中的__call__方法 ,用户发起请求时,才执行。对象() 时调用call(回调函数)。
中间件的实现:在执行call方法之前,做一个操作,call方法执行之后做一个操作。
class Middleware(object): def __init__(self,old): self.old = old def __call__(self, *args, **kwargs): ret = self.old(*args, **kwargs) return ret if __name__ == '__main__': app.wsgi_app = Middleware(app.wsgi_app) app.run()
十、特殊装饰器
1 @app.before_request 正序 返回None或不返回,继续向下执行,否则请求结束。
2 @app.after_request 倒序,参数:response,有返回值。
from flask import Flask app = Flask(__name__) @app.before_request def x1(): print('before:x1') return '滚' @app.before_request def xx1(): print('before:xx1') @app.after_request def x2(response): print('after:x2') return response @app.after_request def xx2(response): print('after:xx2') return response @app.route('/index') def index(): print('index') return "Index" @app.route('/order') def order(): print('order') return "order" if __name__ == '__main__': app.run() 结果: x1 xx1 xx2 x2
3. @app.before_first_request 只在第一次请求前
4. @app.template_global
@app.template_global() def sb(a1, a2): # 在前端渲染 {{sb(1,9)}} return a1 + a2
5. @app.template_filter
@app.template_filter() def db(a1, a2, a3): # 前端渲染 {{ 1|db(2,3) }} return a1 + a2 + a3
6. @app.errorhandler(404) # 编辑错误页面 500、403、404....
@app.errorhandler(404) def not_found(arg): print(arg) return "没找到"
十一、蓝图
使用:看笔记
目标:给开发者提供目录结构
其他作用: - 自定义模板、静态文件的设置
-给 某一类url添加前缀
- 给某一类url添加before_request