from flask import Flask app=Flask(__name__) @app.route("/index") def index(): return "Hello Word" if __name__=="__main__": app.run()
1.新建settings.py 存放配置文件 class Config(object): DEBUG = False SECRET_KEY = "asdfasdfasdf" #上線環境 class ProductionConfig(Config): DEBUG = False #開發環境 class DevelopmentConfig(Config): DEBUG = True #測試環境 class TestingConfig(Config): TESTING = True 其餘文件要引入配置文件中的內容 如: app.config.from_object('settings.DevelopmentConfig') 引入整個py文件:app.config.from_pyfile("settings.py")
before_request和after_request 至關於Django中的中間件 after_request的視圖中必須有參數,且必須有返回值 1.before_request---->目標請求 ----->after_request @app.before_request def a1(): print("a2") @app.after_request def c1(response): print("c1") return response def index(): print("index") return render_template("index.html") 執行順序:a2--->index---->c1 2.在走before_request時若是返回了值,後面的before_request就再也不執行,目標函數也不執行 會把after_request都走一遍 @app.before_request def a1(): print("a1") @app.before_request def d1(response): print("d1") return response @app.after_request def c1(response): print("c1") return response return response def index(): print("index") return render_template("index.html") 執行順序: a1--->d1--->c1
路由的兩種註冊方法: 1.使用裝飾器 @app.route("/login") 2. app.add_url_rule(rule='/login', view_func=index) 1.定義methods @app.route("/login",methods=['GET','POST']) 2.動態路由 URL: http://www.xx.com/index/1/88 @app.route('/index/<string:nid>/<int:num>') 也能夠 @app.route('/index/<nid>/<num>') def index(a,b):pass 3.endpoint ,爲url起別名,根據別名能夠反向生成URL(默認endpoint是函數名) url_for:反向解析 url_for()它把函數名稱做爲第一個參數。它能夠接受任意個關鍵字參數,每一個關鍵字參數對應URL中的變量 1.自定義endpoint @app.route('/user/<username>',endpoint="aaa") def profile(username):print(url_for('aaa',username='zhao') /user/zhao 2.使用默認的endpoint @app.route('/login') def login():pass @app.route('/user/<username>') def profile(username):pass with app.test(): print(url_for('login')) /login print(url_for('login', next='/')) /login?next=/ print(url_for('profile', username='zhao')) /user/zhao 4.支持自定義正則 @app.route('/index/<string:nid>/<int:num>/<regex("\d+"):xxxx>') 5.支持FBV和CBV from flask import Flask,url_for,views class IndexView(views.MethodView): methods = ['GET','POST'] 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='ci')) name="ci" 指別名
from flask import request,render_template,redirect 1.請求: request.method request.args request.form request.cookies request.headers request.path request.full_path request.url request.files obj = request.files['the_file_name'] 2.響應: 1.return "xxxx" 返回字符串 2.return render_template("index.html",msg="xxx") 返回模板 return render_template('html模板路徑',**{"mag="xxx」,arg":12}) 3.return redirect() 重定向 4.response = make_response(render_template('index.html')) 5. response.set_cookie('key', 'value') 6. response.delete_cookie('key') 7.return send_file() def get_img(file_name): file_path = os.path.join(setting.RESOURCE_IMG_PATH,file_name) return send_file(file_path) @app.route('/setco') def setco(): from flask import make_response obj = make_response("返回內容...") obj.set_cookie('a1','123') return obj 給視圖添加裝飾器: - 裝飾器必須設置functools.wappers - 緊挨着放在視圖之上 from functools import wraps def is_login(func): @wraps(func) #保留函數元信息 def inner(*args,**kwargs): user_info = session.get('user') if not user_info: return redirect('/login') ret=func() return ret return inner @app.route("/book") @is_login #必須緊貼着函數 def book(): return "Book"
服務端: def jerd(): return '<h1>jerd</h1>' @app.route('/login', methods=['GET', 'POST']) def login(): return render_template('login.html', ww=jerd) HTML:須要加()和safe <body> {{ww()|safe}} </body> 4.全局函數 1.global: @app.template_global() def test4(arg): return arg + 100 全部視圖中均可以調用: {{ test4(666) }} 2.filter: @app.template_filter() def db(a1, a2, a3): return a1 + a2 + a3 全部視圖中均可以調用: {{ 1|db(2,3)}}
session的本質是字典 flask的session存放在cookie中 1.導入session from flask import session 2.設置key值:app.secret_key="xxxxx" 3.操做: 1.設置:session["zhao"]="zgf" 2.獲取:session.get("zhao") 3.刪除:del session.["zhao"] 在客戶端的cookie中能看到session和sessionid cookie和session的區別? cookie,是保存在用戶瀏覽器端的鍵值對,能夠用來作用戶認證。 session,將用戶會話信息保存在服務端{adfasdfasdf:"...",99dfsdfsdfsd:'xxx'},依賴cookie將每一個用戶的隨機字符串保存到用戶瀏覽器上; django,session默認保存在數據庫;django_session表 flask,session默認將加密的數據寫用戶cookie中。
基於session實現 from flask import flash,get_flashed_messages @app.route('/set_flash') def set_flash(): flash('666',category='error') flash('999',category='log') return "設置成功" @app.route('/get_flash') def get_flash(): data = get_flashed_messages(category_filter=['error']) print(data) return "或成功"
app---藍圖----視圖 1. 目錄結構的劃分(解耦)。 2. 單藍圖中應用before_request 3. URL劃分 app.register_blueprint(account,url_prefix='/user') 4. 反向生成URL url_for('藍圖.函數名') url_for('藍圖.endpoint') url_for('藍圖.endpoint',nid=1) print(url_for('account.login')) 在app下注冊藍圖 app=Flask(__name__) app.register_blueprint(bpmanager) 在視圖中: from flask import Blueprint bpmanager=Blueprint('bpmanager',__name__) @bpmanager.route("/delete/",methods=["GET","POST"]) def delete():pass
1.flask-session的做用:
將flask中的session由加密存到cookie中的方式更換爲放置到其餘的數據源
如:redis/memcached/filesystem/mongodb/sqlalchemy(數據庫)
2.簡述flask-session的原理?
1.請求進來走完before-request後走到open-session方法,該方法從cookie中讀取session_id
對應的隨機字符串。
2.若是未獲取到這個字符串,就建立一個隨機字符串並在內存中建立個特殊的字典
若是能獲取到這個字符串,就根據這個隨機字符串去redis中獲取原來設置的值,並在在內存建立字典
3.在視圖函數中,對內存中的字典進行操做
4.當請求結束時,執行save_session方法,
1.該方法去讀取內存中特殊的字典,並將字典序列化成字符串
2.將字符串寫到redis中
3.將隨機字符串寫到cookie中
操做: 1.安裝:pip3 install flask-session 2.在配置文件中: SESSION_TYPE='redis' SESSION_REDIS = Redis(host='127.0.0.1',port=6379) 3.引入session from flask_session import Session app = Flask(__name__) Session(app)
1.pip3 install DBUtils 2.配置鏈接池: import pymysql from DBUtils.PooledDB import PooledDB, SharedDBConnection POOL = PooledDB( creator=pymysql, # 使用連接數據庫的模塊 maxconnections=20, # 鏈接池容許的最大鏈接數,0和None表示不限制鏈接數 mincached=2, # 初始化時,連接池中至少建立的空閒的連接,0表示不建立 maxcached=5, # 連接池中最多閒置的連接,0和None不限制 maxshared=0, # 連接池中最多共享的連接數量,0和None表示所有共享。PS: 無用,由於pymysql和MySQLdb等模塊的 threadsafety都爲1,全部值不管設置爲多少,_maxcached永遠爲0,因此永遠是全部連接都共享。 blocking=True, # 鏈接池中若是沒有可用鏈接後,是否阻塞等待。True,等待;False,不等待而後報錯 maxusage=None, # 一個連接最多被重複使用的次數,None表示無限制 setsession=[], # 開始會話前執行的命令列表。如:["set datestyle to ...", "set time zone ..."] ping=0, # ping MySQL服務端,檢查是否服務可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always host='127.0.0.1', port=3306, user='root', password='123456', database='day118', charset='utf8' ) 使用: conn = POOL.connection() cursor = conn.cursor() cursor.execute('select * from users') result = cursor.fetchall() conn.close() 將mysql數據庫的操做模塊化: def on_open(cur=pymysql.cursors.DictCursor): conn = POOL.connection() cursor = conn.cursor(cursor=cur) return conn,cursor def on_close(conn,cursor): cursor.close() conn.close() def fetchone(sql,args,cur=pymysql.cursors.DictCursor): """ 獲取單條數據 得到的數據默認以字典的形式,若是要以元祖展現,傳參時設置cur=None """ conn,cursor = on_open(cur) cursor.execute(sql, args) result = cursor.fetchone() return result def fetchall(sql,args,cur=pymysql.cursors.DictCursor): """ 獲取多條數據 """ conn, cursor = on_open(cur) cursor.execute(sql, args) result = cursor.fetchall() return result def exec_sql(sql,args,cur=pymysql.cursors.DictCursor): """ 添加/刪除/修改 :param sql: insert into table(%s,%s) values(....) """ conn, cursor = on_open(cur) cursor.execute(sql, args) conn.commit() 1.DBUtils的做用: 建立數據庫鏈接池 2.簡述數據庫鏈接池的原理? 1.啓動時會在內存中維護一個鏈接池 2.當請求須要鏈接數據庫時則去鏈接池中獲取一個鏈接,若是有空閒的鏈接就去獲取 沒有則等待或報錯 3.使用完畢後,須要將鏈接歸還到鏈接池中 3.鏈接池在最開始啓動時,最大鏈接數是100,是建立了100個連接嗎? 不是
pip3 install wtforms https://www.cnblogs.com/wupeiqi/articles/8202357.html 自定義校驗類: from wtforms.fields import simple from wtforms.fields import html5 from wtforms.fields import core from wtforms import widgets from wtforms import validators from wtforms import Form class TestForm(Form): name = simple.StringField( label='用戶名', validators=[ validators.DataRequired() ], #錯誤信息 widget=widgets.TextInput(), render_kw={'class': 'form-control'} #錯誤信息樣式 ) """ pwd = simple.PasswordField( label='密碼', validators=[ validators.DataRequired(message='密碼不能爲空.') ], widget=widgets.PasswordInput(), render_kw={'class': 'form-control'} ) pwd_confirm = simple.PasswordField( label='重複密碼', validators=[ validators.DataRequired(message='重複密碼不能爲空.'), validators.EqualTo('pwd', message="兩次密碼輸入不一致") ], #自定義了比較 widget=widgets.PasswordInput(), render_kw={'class': 'form-control'} ) email = html5.EmailField( label='郵箱', validators=[ validators.DataRequired(message='郵箱不能爲空.'), validators.Email(message='郵箱格式錯誤') ], widget=widgets.TextInput(input_type='email'), render_kw={'class': 'form-control'} ) gender = core.RadioField( label='性別', choices=( (1, '男'), (2, '女'), ), coerce=int ) city = core.SelectField( label='城市', choices=( ('bj', '北京'), ('sh', '上海'), ) ) hobby = core.SelectMultipleField( label='愛好', choices=( (1, '籃球'), (2, '足球'), ), coerce=int ) favor = core.SelectMultipleField( label='喜愛', choices=( (1, '籃球'), (2, '足球'), ), widget=widgets.ListWidget(prefix_label=False), option_widget=widgets.CheckboxInput(), coerce=int ) """ cls_id = core.SelectField( label='請選擇班級', choices=( ('bj', '北京'), ('sh', '上海'), ) choices=[], coerce=int ) #重寫構造方法 def __init__(self, *args, **kwargs): super(TestForm, self).__init__(*args, **kwargs) self.cls_id.choices = sqlhelper.fetchall(sql='select id,title from classes',args=[],cur=None) #鉤子函數 def validate_name(self,field): """ 對name進行驗證時的鉤子函數 :param field: :return: """ if field != 'root': raise validators.ValidationError("用戶名必須是root") 1.choices字段須要設置coerce=int 2.從數據庫顯示到頁面上的數據要重寫構造方法進行實時更新 3.鉤子函數:validate_字段名():pass 字段驗證後執行定義的鉤子函數 服務端: 1.get請求: if request.method == 'GET': form = TestForm() return render_template('add_cls.html',form=form) 2.post請求。實例化時添加formdata再驗證 form = TestForm(formdata=request.form) if form.validate(): 數據都在form.data 頁面: <form method="post" novalidate> <p> {{form.title.label}} : {{form.title}} <span style="color: red">{{form.title.errors.0}}</span> </p> <input type="submit" value="添加"> </form>
pip3 install pipreqs 進入到項目裏:pipreqs ./ --encoding=utf-8 安裝依賴 install -r requirement.txt
pip3 install virtualenv 在公司中詢問是否安裝虛擬環境 1.須要指定目錄:virtualenv 文件名 virtualenv venv 2.激活 進入到新建項目中的scripts中執行activate cd venv\Scripts 執行active 命令提示符變了,有個(venv)前綴,表示當前環境是一個名爲venv的Python環境。 3.退出:deactivate 此時就回到了正常的環境,如今pip或python均是在系統Python環境下執行。 在linux中安裝虛擬環境 1. pip3 install virtualenv 2.爲virtualenv建立軟鏈接 ln -s /software/py3/bin/virtualenv /usr/bin/virtualenv1 刪除軟鏈接:rm -rf /usr/bin/virtualenv1 3.在當前目錄下建立虛擬環境 virtualenv1 venv1 4.激活 source venv1/bin/activate 5.退出:deactivate
def add(a, b): return a + b; print(add(3, 5)) #8 使用偏函數 import functools def add(a,b): return a+b func1=functools.partial(add,3) print(func1) #functools.partial(<function add at 0x0000028C9C2CFBF8>, 2) print(func1(5)) #8
RequestContext:封裝請求上下文的對象
AppContext:封裝應用上下文的對象
LocalStack : 經過此類實例來操做Local對象,提供了pop、top、push方法
Local:爲每個線程開闢一塊獨立的空間,用來存放數據
LocalProxy:經過此類中的方法來取出request屬性和session屬性
1.
請求上下文:實例化一個RequestContext對象,並將請求的全部相關信息request和session封裝到RequestContext對象中
應用上下文:實例化一個AppContext對象,將current_app, g封裝到AppContext中
2.經過LocalStack類將RequestContext對象,AppContext對象添加到Local中(調用push方法)
Local類爲每個線程開闢一塊獨立的空間,建立了一個字典來保存數據,這個字典的key是用線程的惟一標識存放本身的數據
3.在視圖函數中調用request時會執行LocalProxy中對應的魔法方法__getattr__或__setitem__
又經過偏函數調用Localstark中top方法去Local獲取到數據,取的是列表的最後一個值。
4.請求終止時仍是經過LocalStack的pop方法 將Local中將值在列表中pop掉
內置的session流程:
push中會調用session裏面open_session方法,經過這個方法幫助咱們獲取用戶原有的session信息,有就獲取,沒有就返回一個空的相似字典的數據結構,
賦值給對象中的session,當使用的時候觸發LocalProxy對像裏對魔法方法經過偏函數用Localstark中方法去Local獲取到數據
使用完後,調用session對像的save_session方法,將數據加密寫到用戶的cookie中,這個操做在after_request以後