# Python Flask_變量與請求
###### tags: `python` `flask` `變量` `請求`
flask內有四種上下文全域變量與四種請求
## 上下文全域變量
* 程序上下文
* current_app
* 當前程序
* g
* 請求上下文
* request
* 封裝了client端發出的http請求中的內容
* session
* 用來保存請求之間的資
### current_app
### g
[官方說明](http://dormousehole.readthedocs.io/en/latest/api.html#flask.g)
處理請求作用時臨時儲存的對象,每次請求都會重新設置
:::info
Just store on this whatever you want. For example a database connection or the user that is currently logged in.
什麼都可以保存,資料庫連線或是當前使用者資料
:::
```python
user = getattr(flask.g, 'user', None)
user = flask.g.get('user', None)
```
:::info
It’s now also possible to use the in operator on it to see if an attribute is defined and it yields all keys on iteration.
現在也可以使用in來確認是否存在,也可以透過迭代來操作
:::
### request
### session
## 請求
如果有多個before_request的時候,只要中間有執行return的部份,後續就不再被執行。
* before_first_request
* 註冊一個函數,在處理第一個請求之前執行
* before_request
* 註冊一個函數,在每次請求之前執行
* after_request
* 註冊一個函數,如果沒有未處理的異常拋出,在每次請求之後執行
* teardown_request
* 註冊一個函數,如果有未處理的異常拋出,在每次請求之後執行
### 請求範例
```python
from flask import Flask, g, request
app = Flask(__name__)
@app.before_request
def before_request():
print('before request started')
print(request.url)
@app.before_request
def before_request2():
print('before request started 2')
print(request.url)
g.name = "Test request"
@app.after_request
def after_request(response):
print('after request finished')
print(request.url)
response.headers['key'] = 'value'
return response
@app.teardown_request
def teardown_request(exception):
print('teardown request')
print(request.url)
@app.route('/abc')
def index():
return 'Hello, %s!' % g.name
if __name__ == '__main__':
app.run(debug=True)
```
執行之後,它的執行順序是一路下來的。
但是如果針對第一個before_request做return的話,第二個before_request是不會執行的。
```python
http://127.0.0.1:5000/abc
from flask import Flask, g, request
app = Flask(__name__)
@app.before_request
def before_request():
print('before request started')
print(request.url)
return 'Break!'
@app.before_request
def before_request2():
print('before request started 2')
print(request.url)
g.name = "SampleApp"
@app.after_request
def after_request(response):
print('after request finished')
print(request.url)
response.headers['key'] = 'value'
return response
@app.teardown_request
def teardown_request(exception):
print('teardown request')
print(request.url)
@app.route('/abc')
def index():
return 'Hello, %s!' % g.name
if __name__ == '__main__':
app.run(debug=True)
```
## 範例
### 資料庫連線
```python
@app.before_request
def before_request():
g.db = connect_db()
@app.teardown_request
def teardown_request(exception):
# 取得g的db屬性
db = getattr(g, 'db', None)
# 如果不是沒None的話,即關閉資料庫連線
if db is not None:
db.close()
```
透過flask裝飾器,設置在請求之前做資料庫連線的初始化。
所以設置了一個db屬性給g=connect_db(),並在最後做資料庫的連線關閉。
```python
@app.route('/')
def show_entries():
cur = g.db.execute('select title, text from entries order by id desc')
entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()]
return render_template('show_entries.html', entries=entries)
```
在請求進來之後,就可以直接透過g.db來做資料庫的操作。
```python
@app.route('/add', methods=['POST'])
def add_entry():
if not session.get('logged_in'):
abort(401)
g.db.execute('insert into entries (title, text) values (?, ?)',
[request.form['title'], request.form['text']])
g.db.commit()
flash('New entry was successfully posted')
return redirect(url_for('show_entries'))
```
判斷session若沒有登入訊息,就拋出401異常。
再透過flash送訊息之後重新定向到show_entries。
這邊也注意到一定要使用參數方式來處理,不用字串串接,否則會糟受到SQL injection攻擊