1.請手寫一個flask的hello world。
hello.py中
#coding = utf-8 # 第一步:導入Flask類 from flask import Flask app = Flask(__name__) @app.route("/") def helloworld(): return "<h1>hello world</h1>" if __name__ == " __main__": app.run(debug=True)
2.Flask框架的優勢及適用場景?
優勢:
1.輕量;(Micro Framework)
2.簡潔
3.擴展性好*
4 第三方庫的選擇面廣,開發時可以結合自己喜歡用的輪子,也可以結合強大的python庫
5.核心(werzeug和jinja2),jinja2就是指模板引擎。
應用場景:
適用於小型網站,適用於開發web服務的API;
開發大型網站也毫無壓力,但是代碼架構需要開發者自己設計;
Flask和Nosql數據庫的結合優於django
3.Flask框架組件
flask_sqlalchemy:將Flask和SQLAlchemy很好的結合在一起,如django中的ORM操作
flask_script:用於生成命令,在項目根目錄路徑下使用命令;例如:python manage.py runserver
flask_migrate:用來實現數據庫遷移(依賴flask_script)
flask-session:session放在redis里面
blinker:信號-觸發信號
PS:# flask中的信號blinker 信號主要是讓開發者可是在flask請求過程中定制一些行為。 或者說flask在列表里面預留了幾個空列表,在里面存東西。 簡言之,信號允許某個'發送者'通知'接收者'有事情發生了
4.Flask藍圖的作用
# blueprint把實現不同功能的module分開.也就是把一個大的App分割成各自實現不同功能的module.
# 在一個blueprint中可以調用另一個blueprint的視圖函數, 但要加相應的blueprint名.
通常情況下,我是使用flask框架的項目組織結構是這樣的:
我們看看視圖方法:
#views.py from app import app @app.route('/user/index') def index(): return 'user_index' @app.route('/user/show') def show(): return 'user_show' @app.route('/user/add') def add(): return 'user_add' @app.route('/admin/index') def adminindex(): return 'admin_index' @app.route('/admin/show') def adminshow(): return 'admin_show' @app.route('/admin/add') def adminadd(): return 'admin_add'
#從視圖方法中,我們看到有6個視圖,分別對應admin,user兩個不同用戶的3個功能index,add,show.
這樣寫顯然沒問題,但是明顯與python提倡的模塊化沖突;
當然根據Pythonic特點,我們肯定希望盡可能的把代碼盡量的模塊化,讓我們的代碼看起來更加的優雅和順暢,這個時候flask.Blueprint(藍圖)就派上用場了
一個藍圖定義了可用於單個應用的視圖,模板,靜態文件等等的集合
上面的例子中只有兩個組件(模塊)admin,user,我們可以創建名為admin.py和user.py的兩個文件,分別在里面創建兩個藍圖的實例對象admin,user.
#admin.py from flask import Blueprint,render_template, request admin = Blueprint('admin',__name__) @admin.route('/index') def index(): return render_template('admin/index.html') @admin.route('/add') def add(): return 'admin_add' @admin.route('/show') def show(): return 'admin_show' #要想創建一個藍圖對象,你需要import flask.Blueprint()類並用參數name和import_name初始化。import_name通常用__name__,一個表示當前模塊的特殊的Python變量,作為import_name的取值。
#user.py
from flask import Blueprint, render_template, redirect user = Blueprint('user',__name__) @user.route('/index') def index(): return render_template('user/index.html') @user.route('/add') def add(): return 'user_add' @user.route('/show') def show(): return 'user_show'
視圖函數已經分開了 再看看view.py
#view.py from app import app from .admin import admin from .user import user #這里分別給app注冊了兩個藍圖admin,user #參數url_prefix='/xxx'的意思是設置request.url中的url前綴, #即當request.url是以/admin或者/user的情況下才會通過注冊的藍圖的視圖方法處理請求並返回 app.register_blueprint(admin,url_prefix='/admin') app.register_blueprint(user, url_prefix='/user')
再看看使用藍圖后的項目結構:
如果項目不大的話就沒有必要使用藍圖了,我們甚至可以把除了所有css,js,html的代碼都寫到一個文件中去。
5.列舉Flask使用的第三方組件
# 第三方組件:
Wtforms:快速創建前端標簽、文本校驗
dbutile:創建數據庫連接池
gevent-websocket:實現websocket
# 自定義Flask組件
auth認證
參考flask-login
6.簡述Flask上下文管理流程。
Flask中有兩種上下文,請求上下文和應用上下文
request和session都屬於請求上下文對象。
request:封裝了HTTP請求的內容,針對的是http請求。舉例:user = request.args.get('user'),獲取的是get請求的參數。
session:用來記錄請求會話中的信息,針對的是用戶信息。舉例:session['name'] = user.id,可以記錄用戶信息。還可以通過session.get('name')獲取用戶信息
current_app和g都屬於應用上下文對象。
current_app:表示當前運行程序文件的程序實例。
g:處理請求時,用於臨時存儲的對象,每次請求都會重設這個變量。比如:我們可以獲取一些臨時請求的用戶信息。
當調用app = Flask(_name_)的時候,創建了程序應用對象app;
request 在每次http請求發生時,WSGI server調用Flask.call();然后在Flask內部創建的request對象;
app的生命周期大於request和g,一個app存活期間,可能發生多次http請求,所以就會有多個request和g。
最終傳入視圖函數,通過return、redirect或render_template生成response對象,返回給客戶端。
他們的區別:
請求上下文:保存了客戶端和服務器交互的數據。 應用上下文:在flask程序運行過程中,保存的一些配置信息,比如程序文件名、數據庫的連接、用戶信息等
# a、簡單來說,falsk上下文管理可以分為三個階段: 1、'請求進來時':將請求相關的數據放入上下問管理中 2、'在視圖函數中':要去上下文管理中取值 3、'請求響應':要將上下文管理中的數據清除# # b、詳細點來說: 1、'請求剛進來': 將request,session封裝在RequestContext類中 app,g封裝在AppContext類中 並通過LocalStack將requestcontext和appcontext放入Local類中 2、'視圖函數中': 通過localproxy--->偏函數--->localstack--->local取值 3、'請求響應時': 先執行save.session()再各自執行pop(),將local中的數據清除
7.Flask中g的作用
g:gloal
1.g對象是專門用來來保存用戶數據的;
2.g對象在一次請求中的所有的代碼的地方,都是可以使用的
# g是貫穿於一次請求的全局變量,當請求進來將g和current_app封裝為一個APPContext類, # 再通過LocalStack將Appcontext放入Local中,取值時通過偏函數在LocalStack、local中取值; # 響應時將local中的g數據刪除
8.如何編寫flask的離線腳本
9.Flask中上下文管理主要是涉及到了哪些相關的類?並描述類主要的作用
RequestContext #封裝進來的請求(賦值給ctx) AppContext #封裝app_ctx LocalStack #將local對象中的數據維護成一個棧(先進后出) Local #保存請求上下文對象和app上下文對象
10.為什么要Flask把Local對象中的值stack維護程一個列表
# 因為通過維護成列表,可以實現一個棧的數據結構,進棧出棧時只取一個數據,巧妙的簡化了問題。 # 還有,在多app應用時,可以實現數據隔離;列表里不會加數據,而是會生成一個新的列表 # local是一個字典,字典里key(stack)是唯一標識,value是一個列表
11.Flask中多app應用如何編寫?
請求進來時,可以根據URL的不同,交給不同的APP處理。藍圖也可以實現
#app1 = Flask('app01') #app2 = Flask('app02') #@app1.route('/index') #@app2.route('/index2')
源碼中在DispatcherMiddleware類里調用app2.__call__,
原理其實就是URL分割,然后將請求分發給指定的app。
之后app也按單app的流程走。就是從app.__call__走。
12.在Flask中實現WebSocket需要什么組件?
gevent-websocet
13.wtforms組件的作用?
定義:WTForms是一個支持多個web框架的form組件,主要用於對用戶請求數據進行驗證。
兩種導入方式:
from wtforms import Form from flask_wtf import FlaskForm 需要設置csrf
安裝:
pip3 install wtforms
作用:
快速創建前端標簽、文本校驗:如django的ModelForm
14.Flask框架默認的session處理機制?
15.解釋Flask框架中Local對象和threadinglocal對象的區別?
# a.threading.local
作用:為每個線程開辟一塊空間進行數據存儲(數據隔離)。
問題:自己通過字典創建一個類似於threading.local的東西。 storage = { 4740: {val: 0}, 4732: {val: 1}, 4731: {val: 3}, }
# b.自定義Local對象
作用:為每個線程(協程)開辟一塊空間進行數據存儲(數據隔離)。
class Local(object): def __init__(self): object.__setattr__(self, 'storage', {}) def __setattr__(self, k, v): ident = get_ident() if ident in self.storage: self.storage[ident][k] = v else: self.storage[ident] = {k: v} def __getattr__(self, k): ident = get_ident() return self.storage[ident][k] obj = Local() def task(arg): obj.val = arg obj.xxx = arg print(obj.val) for i in range(10): t = Thread(target=task, args=(i,)) t.start()
16.SQLAlchemy中的session和scoped_session的區別?
# Session:
由於無法提供線程共享功能,開發時要給每個線程都創建自己的session
打印sesion可知他是sqlalchemy.orm.session.Session的對象
# scoped_session:
為每個線程都創建一個session,實現支持線程安全
在整個程序運行的過程當中,只存在唯一的一個session對象。
創建方式:通過本地線程Threading.Local()
# session=scoped_session(Session)
創建唯一標識的方法(參考flask請求源碼)
17.SQLAlchemy如何執行原生SQL?
# 使用execute方法直接操作SQL語句(導入create_engin、sessionmaker)
engine=create_engine('mysql://root:pwd@127.0.0.1/database?charset=utf8')
DB_Session = sessionmaker(bind=engine)
session = DB_Session()
session.execute('select * from table...;')
18.ORM的實現原理?
# ORM的實現基於以下三點
映射類:描述數據庫表結構,
映射文件:指定數據庫表和映射類之間的關系
數據庫配置文件:指定與數據庫連接時需要的連接信息(數據庫、登錄用戶名、密碼or連接字符串)
19.DBUtils模塊的作用?
# DBUtils是數據庫連接池模塊
使用模式:
1、為每個線程創建一個連接,連接不可控,需要控制線程數
2、創建指定數量的連接在連接池,當線程訪問的時候去取,不夠了線程排隊,直到有人釋放*
兩種寫法:
1.用靜態方法裝飾器,通過直接執行類的方法來連接使用數據庫;
2.通過實例化對象,通過對象調用方法使用語句;
20.SQLAlchemy中的如何為表設置引擎和字符編碼?
sqlalchemy設置編碼字符集,一定要在數據庫訪問的URL上增加'charset=utf8',否則數據庫的連接就不是'utf8'的編碼格式
1. 設置引擎編碼方式為utf8:
engine = create_engine('mysql://root:root@localhost:3306/test2?charset=utf8',echo=True)
2. 設置數據庫表編碼方式為utf8:
engine = create_engine("mysql+pymysql://root:123456@127.0.0.1:3306/sqldb01?charset=utf8")
class UserType(Base): __tablename__ = 'usertype' i d = Column(Integer, primary_key=True) caption = Column(String(50), default='管理員') # 添加配置設置編碼 __table_args__ = { 'mysql_charset':'utf8' }
這樣生成的SQL語句就自動設置數據表編碼為utf8了,__table_args__還可設置存儲引擎、外鍵約束等等信息。
21.SQLAlchemy中如何設置聯合唯一索引
通過'UniqueConstraint'字段來設置聯合唯一索引
__table_args=(UniqueConstraint('h_id','username',name='_h_username_uc'))
#h_id和username組成聯合唯一約束