Flask總結

1.配置文件

2.before_request/after_request

3.路由系統

4.視圖

5.模板

6.session

7.flash

8.藍圖(blueprint)

flask-組件

1.flask-session

2.DBUtils

3.wtforms

4.SQLAlchemy

5.flask-script

6.flask-migrate

偏函數

上下文管理

用flask寫一個hello world文件

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  

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" 指別名
View Code

         視圖     

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"
View Code

         模板     

Flask使用的是Jinja2模板,因此其語法和Django無差異
1.支持python語法
2.支持模板繼承
3.自定義函數

服務端:
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   

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中。

      flash,閃現   

基於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 "或成功"

    藍圖(blueprint)  

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

    flask-session   

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)

   DBUtils 數據庫鏈接池 

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個連接嗎?
不是
View Code

  wtforms:對用戶請求數據作表單驗證  

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>
View Code

   pipreqs:查看安裝包依賴  

pip3 install pipreqs 
進入到項目裏:pipreqs ./ --encoding=utf-8
安裝依賴
install -r requirement.txt

virtualenv 建立虛擬環境(純淨的環境)

 

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

 

   偏函數  

使用偏函數能夠經過有效地「凍結」那些預先肯定的參數,而後在運行時,當得到須要的剩餘參數後,能夠將他們解凍,傳遞到最終的參數中
應用場景:調用sum函數時,咱們已經知道了其中的一個參數,咱們能夠經過這個參數,從新綁定一個函數,而後加上其餘參數去調用便可

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以後
相關文章
相關標籤/搜索