flask
知识点
1.谈谈你对django和flask的认识。
2.flask和django最大的不同点:request/session
session的存储方式不同
django 存放在数据库 flask 存放在cookie里面
中间件不同
django 有许多内置的, flask 需要自己写
- 给你一个路径 “settings.Foo”,可以找到类并获取去其中的大写的静态字段。 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))
1.配置文件
app.config.from_object("settings.DevelopmentConfig")
# setting.py 配置类
class Config(object): DEBUG = False TESTING = False SECRET_KEY = "asdfasdfas23" DATABASE_URI = 'sqlite://:memory:' # 设置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(hours=1) # 其他配置,实现多情景下配置,app.py只需要改对应的配置类 class ProductionConfig(Config): DATABASE_URI = 'mysql://user@localhost/foo' class DevelopmentConfig(Config): DEBUG = True class TestingConfig(Config): TESTING = True
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_pyfile("python文件名称") 如: settings.py DEBUG = True app.config.from_pyfile("settings.py") app.config.from_envvar("环境变量名称") 环境变量的值为python文件名称名称,内部调用from_pyfile方法 app.config.from_json("json文件名称") JSON文件名称,必须是json格式,因为内部会执行json.loads app.config.from_mapping({'DEBUG':True}) 字典格式 app.config.from_object("python类或类的路径") app.config.from_object('pro_flask.settings.TestingConfig') 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: 从sys.path中已经存在路径开始写 PS: settings.py文件默认路径要放在程序root_path目录,如果instance_relative_config为True,则就是instance_path目录
2. 路由系统
- endpoint,反向生成URL,默认函数名
- url_for('endpoint') / url_for("index",nid=777)
#反向解析 #参数
- 动态路由:
@app.route('/index/<int:nid>',methods=['GET','POST'])
def index(nid):
print(nid)
return "Index"
@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, }
def auth(func): def inner(*args, **kwargs): print('before') result = func(*args, **kwargs) print('after') return result return inner @app.route('/index.html',methods=['GET','POST'],endpoint='index') @auth def index(): return 'Index' 或 def index(): return "Index" self.add_url_rule(rule='/index.html', endpoint="index", view_func=index, methods=["GET","POST"]) or app.add_url_rule(rule='/index.html', endpoint="index", view_func=index, methods=["GET","POST"]) app.view_functions['index'] = index 或 def auth(func): def inner(*args, **kwargs): print('before') result = func(*args, **kwargs) print('after') return result return inner class IndexView(views.View): methods = ['GET'] decorators = [auth, ] def dispatch_request(self): print('Index') return 'Index!' app.add_url_rule('/index', view_func=IndexView.as_view(name='index')) # name=endpoint 或 class IndexView(views.MethodView): methods = ['GET'] decorators = [auth, ] def get(self): return 'Index.GET' def post(self): return 'Index.POST' app.add_url_rule('/index', view_func=IndexView.as_view(name='index')) # name=endpoint @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, 子域名访问 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() a.注册路由原理
3. FBV 视图处理
4.请求
from flask import Flask from flask import request,render_template,redirect,make_response app = Flask(__name__) @app.route('/login.html', methods=['GET', "POST"]) def login(): # 请求相关信息 # request.method # request.args # get的参数 # 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 return "内容" if __name__ == '__main__': app.run()
5. 响应
响应体: return “asdf” return jsonify({'k1':'v1'}) return render_template('xxx.html') return redirect() 定制响应头: obj = make_response("asdf") obj.headers['xxxxxxx'] = '123' # 定制响应头 obj.set_cookie('key', 'value') return obj
示例程序:学生管理 版本一: @app.route('/index') def index(): if not session.get('user'): return redirect(url_for('login')) return render_template('index.html',stu_dic=STUDENT_DICT) 版本二: 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')
6. 模板渲染
- 基本数据类型:可以执行python语法,如:dict.get() list['xx']
- 传入函数
- django,自动执行
- flask,不自动执行 需要加括号 func()
- 全局定义函数
多个地方调用的时候,就不用挨个传
app.py @app.template_global() def sb(a1, a2): # {{sb(1,9)}} return a1 + a2 @app.template_filter() def db(a1, a2, a3): # {{ 1|db(2,3) }} # 可以if 判断 return a1 + a2 + a3
- 模板继承
layout.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> tpl.html {% extends "layout.html"%} {% block content %} {{users.0}} {% endblock %} - include 导入子页面 {% include "form.html" %} form.html <form> asdfasdf asdfasdf asdf asdf </form>
重复使用模块,方便调用 定义好的宏 {% macro ccccc(name, type='text', value='') %} <h1>宏</h1> <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> <input type="submit" value="提交"> {% endmacro %} 调用传参(类似函数) {{ ccccc('n1') }} {{ ccccc('n2') }}
- 前端: {{u|safe}}
- 前端: MarkUp("asdf")
7. session
当请求刚到来:flask读取cookie中session对应的值:eyJrMiI6NDU2LCJ1c2VyIjoib2xkYm95,将该值解密并反序列化成字典,放入内存以便视图函数使用。
操作的session 是字典。反回的时候将字典序列化,放到cookie反回给用户
视图函数:
@app.route('/ses')
def ses():
session['k1'] = 123
session['k2'] = 456
del session['k1']
return "Session"
session['xxx'] = 123
session['xxx']
当请求结束时,flask会读取内存中字典的值,进行序列化+加密,写入到用户cookie中。
SESSION REFRESH EACH REQUEST=True 在每次(最后)访问的基础时间上向后推移过期时间
False 在第一次访问的基础时间向后推移
更多session配置在默认配置里面更改
8. 闪现
在session中存储一个数据,读取时通过pop将数据移除。
from flask import Flask,flash,get_flashed_messages @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"
9. 中间件
跟django的中间件不一样,需要自己定制
基本不用,用before_request
- 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()
对象() 执行__call__方法 class Test(object): def __init__(self,name): self.name = name print('__init__') def __call__(self, *args, **kwargs): print('__call__') a = Test('dsd') a() """ __init__ __call__ """
10. 特殊装饰器
1. before_request 2. after_request 示例: 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() 3. before_first_request from flask import Flask app = Flask(__name__) @app.before_first_request def x1(): print('123123') @app.route('/index') def index(): print('index') return "Index" @app.route('/order') def order(): print('order') return "order" if __name__ == '__main__': app.run() 4. template_global 5. template_filter 6. errorhandler @app.errorhandler(404) def not_found(arg): print(arg) return "没找到"
flask 在before_request有return 会把after走完
django 不是 紫色--django