配置文件html
路由系統 前端
視圖python
請求相關mysql
響應 正則表達式
模板渲染redis
session sql
閃現django
中間件 json
藍圖(blueprint)flask
給你一個路徑 「settings.Foo」,能夠找到類並獲取其中的大寫的靜態字段。
class Foo: DEBUG = True TEST = True
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))
importlib模塊
實現機制:根據字符串的形式導入模塊,經過反射找到裏面的內容,有一個特色,只有所有大寫才能被讀到。
導入方式:app.config.from_object()
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目錄
經常使用:app.config.from_object()
本質:帶參數的裝飾器和閉包實現的。
@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('/index/<int:nid>',methods=["GET","POST"]) def index(nid): url_for("index",nid=1) #/index/1 return "Index"
FBV
# 請求相關信息 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)) #將文件保存,寫到本地的路徑
# 響應相關信息 return "字符串" return jsonify({'k1':'v1'}) #內部幫咱們序列化 return render_template('html模板路徑',**{}) return redirect('/index.html') #重定向
注:jsonify內部幫咱們序列化,跟django的jsonresponse有點類似。
咱們返回的都是響應體,頁面能夠看到的。那咱們如何加響應頭?
若是咱們想要返回相關的信息時,能夠經過make_response將咱們的內容封裝起來。
response = make_response(render_template('index.html')) # response是flask.wrappers.Response類型 response.headers['X-Something'] = 'A value' #加響應頭 return response
那咱們能夠設置cookie嗎?
response = make_response(render_template('index.html')) # response是flask.wrappers.Response類型 response.delete_cookie('key') response.set_cookie('key', 'value') return response
Flask使用的是Jinja2模板,因此其語法和Django無差異
Flask中自定義模板方法的方式和Bottle類似,建立一個函數並經過參數的形式傳入render_template,如:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <h1>自定義函數</h1> {{ww()|safe}} </body> </html>
#!/usr/bin/env python # -*- coding:utf-8 -*- from flask import Flask,render_template app = Flask(__name__) def wupeiqi(): return '<h1>yaya</h1>' @app.route('/login', methods=['GET', 'POST']) def login(): return render_template('login.html', ww=yaya) app.run()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% macro input(name, type='text', value='') %} <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> {% endmacro %} {{ input('n1') }} {% include 'tp.html' %} <h1>asdf{{ v.k1}}</h1> </body> </html>
注意:Markup等價django的mark_safe
能夠執行python語法,如:dict.get(),list["xx"]
Django中函數自動加括號執行;
Flask中不自動執行,須要本身主動執行,能夠傳參數。
@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) }} 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 "form.html" %} form.html <form> asdfasdf asdfasdf </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")
注:Flask中的markup至關於Django中的mark_safe.
除請求對象以外,還有一個 session 對象。它容許你在不一樣請求間存儲特定用戶的信息。它是在 Cookies 的基礎上實現的,而且對 Cookies 進行密鑰簽名要使用會話,你須要設置一個密鑰。
設置:session['username'] = 'xxx'
from flask import Flask, session, redirect, url_for, escape, request app = Flask(__name__) @app.route('/') def index(): if 'username' in session: return 'Logged in as %s' % escape(session['username']) return 'You are not logged in' @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': session['username'] = request.form['username'] return redirect(url_for('index')) return ''' <form action="" method="post"> <p><input type=text name=username> <p><input type=submit value=Login> </form> ''' @app.route('/logout') def logout(): # remove the username from the session if it's there session.pop('username', None) return redirect(url_for('index')) # set the secret key. keep this really secret: app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
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)
#!/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()
以加密的形式放到瀏覽器的cookie裏面。
用戶瀏覽器能夠禁用cookie,禁用掉以後就不能用。用戶登陸就不能成功。
請求進來去cookie中把數據拿到,拿到以後將數據解密並反序列化成字典放到內存,讓視圖函數使用,視圖函數使用完交給其餘人,再進行序列化加密放到session中去,
本質:放到session,再給他移除掉。
當請求剛到來:flask讀取cookie中session對應的值:eyJrMiI6NDU2LCJ1c2VyIjoib2xkYm95,將該值解密並反序列化成字典,放入內存以便視圖函數使用。
視圖函數:
@app.route('/ses') def ses(): session['k1'] = 123 session['k2'] = 456 del session['k1'] return "Session"
session是以字典的形式保存在cookie中,字典有啥操做,它就有啥操做。
當請求結束時,flask會讀取內存中字典的值,進行序列化+加密,寫入到用戶cookie中。
能夠在配置文件中對相應的配置進行修改。
生命週期默認是31天,能夠修改。Django中cookie生命週期默認是2周。
是一個基於Session實現的用於保存數據的集合,其特色是:使用一次就刪除。
在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"
請求執行wsgi.app以前和以後定製一些操做,用的是call方法。
Django和Falsk請求源碼的入口就是call方法。
用戶發起請求時,才執行。
在執行call方法以前,作一個操做,call方法執行以後作一個操做。
方式一:改源碼
方式二:
class Middleware(object): def __init__(self,old): self.old = old def __call__(self, *args, **kwargs): #四、瀏覽器發送請求,觸發__call__方法 ret = self.old(*args, **kwargs) #五、賦值 return ret if __name__ == '__main__': #1 app.wsgi_app = Middleware(app.wsgi_app) #二、先會給app.wsgi_app賦值 app.run() #三、啓動werkzeug服務器,等待請求
Django中的中間件是請求和響應時作一些操做,而Flask中間件是自定義一些操做。在請求執行以前和執行以後定製一些操做。
Flask源碼入口:
給開發者提供目錄結構
一、若是某一個藍圖想在別的地方找模板,怎麼辦?
如上所示,在實例化藍圖中能夠自定義模板位置。那藍圖若是想用模板怎麼找?
先找目錄下的template下的,沒有才去藍圖中找。跟Django同樣。(先在項目中找,沒找到再去app中去找。)
二、還能夠給某一類加前綴。
在每次執行前都要加上前綴,不然報錯。
三、能夠給某一類添加before_request
from flask import Blueprint,render_template ac = Blueprint('ac',__name__,template_folder="xxxxx") @ac.before_request def x1(): print('app.before_request') @ac.route('/login') def login(): return render_template('login.html') @ac.route('/logout') def logout(): return 'Logout'
這個何時用到呢?
登陸認證。
只要登陸成功才能訪問的藍圖中就加before_request.
flask與django1.9版本以前,無論請求函數有沒有return,中間件響應函數都執行。
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()
項目啓動起來,第一次請求才執行。
是一個標識,最開始是True,第一次請求以後改成False,就再也不執行。
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()
給模板用
@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) }} return a1 + a2 + a3
定製錯誤頁面
@app.errorhandler(404) def not_found(arg): print(arg) return "沒找到"