Flaks框架(g對象,session,數據庫連接池,信號,flask-script,SQLAlchemy(ORM))

[toc]
## 一:g對象

* ### 簡介

```python
1.專門用來存儲用戶信息的g對象,g的全稱的爲global,g對象是全局的
2.g對象在一次請求中的所有的代碼的地方,都是可以使用的,g對象在當次請求中一直有效
```

### 1.g對象和session的區別

```python
1.session對象是可以跨request的,只要session還未失效,不同的request的請求會獲取到同一個session,
2.但是g對象不是,g對象不需要管過期時間,請求一次就g對象就改變了一次,或者重新賦值了一次
```

##### 2.g對象實戰代碼

```python
from flask import Flask,g,request,session

app = Flask(__name__)

@app.before_request
def first():
session['name']='dlrb'
request.form='egon'
g.name='lqz'

@app.after_request
def after(response):
print('11111',g.name)
return response

@app.route('/')
def hello_world():
print('00000',g.name)
return 'Hello World!'

if __name__ == '__main__':
app.run()
```

![image-20220508132622278](https://s2.loli.net/2022/05/08/yScbUwui5xVKvhn.png)

 

## 二:flask-session(藉助於第三方插件連接redis保存session )

作用:將默認保存的簽名cookie中的值 保存到 redis/memcached/file/Mongodb/SQLAlchemy

安裝:pip3 install flask-session

### 1.方式一:

```python
from flask import Flask,g,request,session

from flask_session import RedisSessionInterface
app = Flask(__name__)

app.debug=True # 開啓debug,沒上線爲True,方便查詢錯誤

app.secret_key='asdfasdfasdf' # 密鑰
# 方式一
from redis import Redis
conn=Redis(host='127.0.0.1',port=6379)

# 使用第三方查詢RedisSessionInterface進行將session存入redis
app.session_interface=RedisSessionInterface(redis=conn,key_prefix='flask_session')
# redis : redis地址,端口(不填,默認本地)
# key_prefix : 前綴


@app.route('/')
def hello_world():
session['name']='lqz'
return 'Hello World!'

if __name__ == '__main__':
app.run()
```

### 2.方式二(flask使用第三方插件的通用方案):

```python
from flask_session import Session
from redis import Redis
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_KEY_PREFIX']='flask_session'
app.config['SESSION_REDIS'] = Redis(host='127.0.0.1',port='6379')
Session(app) # 將app傳入session內

@app.route('/')
def hello_world():
session['name']='lqz'
return 'Hello World!'

if __name__ == '__main__':
app.run()
```

### 3.效果1:(訪問地址瀏覽器生成session)

![image-20220508140303928](https://s2.loli.net/2022/05/08/Rm3G8VeOgDfC6pu.png)

### 4.效果2:(session存入redis)

![image-20220508135056632](https://s2.loli.net/2022/05/08/HNyOxaiQnV2LWAb.png)

### 5.如何設置session的過期時間?

```python
#源碼expires = self.get_expiration_time(app, session)
'PERMANENT_SESSION_LIFETIME': timedelta(days=31),#這個配置文件控制
```

### 6.設置cookie時,如何設定關閉瀏覽器則cookie失效

```python
app.session_interface=RedisSessionInterface(conn,key_prefix='lqz',permanent=False) # permanent=False 的情況下就會關閉瀏覽器,cookie失效
```

 

## 三:數據庫連接池

### 1.pymsql鏈接數據庫

```python
from flask import Flask
import time
import pymysql
app = Flask(__name__)
app.debug=True

app.secret_key='asdfasdfasdf'

@app.route('/')
def hello_world():
# pymysql連接數據庫(指定數據庫信息)
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='1', database='luffy')
cursor = conn.cursor() # 獲得遊標對象
cursor.execute('select * from luffy_order') # 查詢luffy_order表
time.sleep(1)
print(cursor.fetchall()) # 獲取所有
return 'Hello World!'


if __name__ == '__main__':
app.run()
```

### 2.問題:

```python
# 問題:
1.如果使用全局連接對象,會導致數據錯亂
# 問題二:
2.如果在視圖函數中創建數據庫連接對象,會導致連接數過多
```

### 3.解決:

```python
使用數據庫連接池 DBUtils
```

### 4.數據庫連接池版

```python
from dbutils.pooled_db import PooledDB
import pymysql

POOL=PooledDB(
creator=pymysql, # 使用鏈接數據庫的模塊
maxconnections=6, # 連接池允許的最大連接數,0和None表示不限制連接數
mincached=2, # 初始化時,鏈接池中至少創建的空閒的鏈接,0表示不創建
maxcached=5, # 鏈接池中最多閒置的鏈接,0和None不限制
maxshared=3,
# 鏈接池中最多共享的鏈接數量,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='1',
database='luffy',
charset='utf8')


# 導入進程
from threading import Thread

def task():
# 去池中獲取連接
conn = POOL.connection()
# 獲取遊標
cursor = conn.cursor()
cursor.execute('select * from luffy_order') # 查詢luffy_order表
print(cursor.fetchall()) # 獲取所有
for i in range(100): # 循環100個進程
t=Thread(target=task) # 進程執行
t.start()

# mysql可以看到當前有多少個連接數
```

![image-20220508144545907](https://s2.loli.net/2022/05/08/TWuwnyD1Kvl7k38.png)

 

## 四:信號

```python
# Flask框架中的信號基於blinker,其主要就是讓開發者可是在flask執行過程中定製一些用戶行爲
```

### 1.內置信號

```python
# pip3 install blinker


## flask中有內置信號
# 什麼時候觸發的
request_started = _signals.signal('request-started') # 請求到來前執行
request_finished = _signals.signal('request-finished') # 請求結束後執行

before_render_template = _signals.signal('before-render-template') # 模板渲染前執行
template_rendered = _signals.signal('template-rendered') # 模板渲染後執行

got_request_exception = _signals.signal('got-request-exception') # 請求執行出現異常時執行

request_tearing_down = _signals.signal('request-tearing-down') # 請求執行完畢後自動執行(無論成功與否)
appcontext_tearing_down = _signals.signal('appcontext-tearing-down')# 應用上下文執行完畢後自動執行(無論成功與否)

appcontext_pushed = _signals.signal('appcontext-pushed') # 應用上下文push時執行
appcontext_popped = _signals.signal('appcontext-popped') # 應用上下文pop時執行
message_flashed = _signals.signal('message-flashed') # 調用flask在其中添加數據時,自動觸發
```

### 2.內置信號的使用

### 3.內置信號使用步驟:

```python
1.寫一個函數
2.跟內置信號綁定
3.以後只要觸發內置信號,函數就會執行
```

```python
from flask import Flask,signals,render_template
from flask.signals import _signals
app = Flask(__name__)

# 往信號中註冊函數
def func(*args,**kwargs):
print('觸發型號',args,kwargs)
# 信號一般用來記錄日誌
# signals信號.內置信號(請求到來前執行).connect(執行函數)
signals.request_started.connect(func)

# 給模板渲染前編寫信號
def template_before(*args,**kwargs):
print(args)
print(kwargs)
print('模板開始渲染了')
# signals信號.內置信號(模板渲染前執行).connect(執行函數)
signals.before_render_template.connect(template_before)
```

### 4.自定義信號

### 5.自定製信號流程

```python
1 寫一個信號
2 寫一個函數
3 信號綁定函數
4 觸發信號
```

```python
# 自定義信號
# 自定製信號 = signals.signal('自定製信號名稱')
before_view = _signals.signal('before_view')

# 寫函數
def test(*args,**kwargs):
print('我執行了')
print(args)
print(kwargs)

# 綁定給信號
# before_view信號.connect(執行函數)
before_view.connect(test)

@app.route('/index',methods=['GET',"POST"])
def index1():
# 觸發信號
# before_view信號.send發送(關鍵字,關鍵字)
before_view.send(name='lqz',age=19)
print('視圖')
return render_template('index.html',a='lqz')

if __name__ == '__main__':
app.run(port=8080)
app.__call__
```

![image-20220508160203073](https://s2.loli.net/2022/05/08/kiW5zsVMN7hBKT9.png)

##

 

## 五:flask-script

```python
# 1.用於實現類似於django中 python3 manage.py runserver ...類似的命令
```

### 1.安裝

```python
pip3 install flask-script
```

### 2.文件名稱(啓動的manage.py):

##### manage.py

```python
from flask_script import Manager
from flask import Flask
app = Flask(__name__)

# 傳入app生成flask_script對象
manager=Manager(app)

if __name__ == '__main__':
manager.run()
#python3 manage.py runserver --help
```

以後執行(啓動)直接:python3 manage.py runserver

![image](https://img2022.cnblogs.com/blog/2608805/202205/2608805-20220511013541808-1725143891.png)


### 3.自定製命令

```python
@manager.command
def custom(arg):
"""
自定義命令
python manage.py custom 123
:param arg:
:return:
"""
print(arg)

@manager.option('-n', '--name', dest='name')
@manager.option('-u', '--url', dest='url')
def cmd(name, url):
"""
自定義命令(-n也可以寫成--name)
執行: python manage.py cmd -n lqz -u http://www.oldboyedu.com
執行: python manage.py cmd --name lqz --url http://www.oldboyedu.com
:param name:
:param url:
:return:
"""
print(name, url)
```

![image-20220508162024888](https://s2.loli.net/2022/05/08/IyjKkG6Vf7hs9rw.png)

### 4.自定製有什麼用?

```python
1.可以把excel的數據導入數據庫,定製個命令,去執行
```

 

## 六:SQLAlchemy(orm框架)

```python
1.orm框架SQLAlchemy,第三方,獨立使用,集成到web框架中
2.django的orm框架
```

### 1.安裝SQLAlchemy

```python
pip install SQLAlchemy
```

#### 2.sqlalchemy執行ORM

```python
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from models import Book,Hobby,Person

# 指定create_engine對象,sqlalchemy指定數據庫
engine = create_engine("mysql+pymysql://root:[email protected]:3306/aaa", max_overflow=0, pool_size=5) # 連接池大小

# bind綁定engine
# 生成Connection對象
Connection = sessionmaker(bind=engine)

# 每次執行數據庫操作時,都需要創建一個Connection
con = Connection()

# ############# 執行ORM操作 #############
# 單表插入一條數據
# book=Book(name='金',price=11)
# con.add(book)

## 一對多關係插入
# hobby=Hobby(caption='足球')
# person=Person(name='lqz',hobby_id=1)
# con.add(hobby)
# con.add(person)

# 一對多插入

# hobby=Hobby(caption='橄欖球')
# person=Person(name='egon',hobby=hobby)
# con.add(hobby)
# con.add(person)

# 查詢egon
# egon=con.query(Person).filter_by(name='egon').first()
# print(egon.hobby_id)
# print(egon.hobby.caption) # 拿到hobby對象 ,正向查詢:字段名

glq=con.query(Hobby).filter_by(caption='橄欖球').first()
pers=glq.pers #反向查詢,按 backref='pers'
print(pers)
for p in pers:
print(p.name)

# 提交事務
con.commit()
# 關閉session,其實是將連接放回連接池
con.close()
```

#### 3.models模型層

```python
import datetime
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index
from sqlalchemy.orm import relationship
Base = declarative_base()

class Users(Base): # Base基類(相當於Django中的models.MODELS)
__tablename__ = 'users' # 數據庫表名稱
id = Column(Integer, primary_key=True) # id 主鍵
name = Column(String(32), index=True, nullable=False) # name列,索引,不可爲空
email = Column(String(32), unique=True)
#datetime.datetime.now不能加括號,加了括號,以後永遠是當前時間
ctime = Column(DateTime, default=datetime.datetime.now)
extra = Column(Text, nullable=True)

__table_args__ = (
# id和name (聯合唯一名稱:uix_id_name)
UniqueConstraint('id', 'name', name='uix_id_name'),
# name和email是聯合索引 索引名稱(ix_id_name)
Index('ix_id_name', 'name', 'email'), #索引
)


class Book(Base): # 表模型
__tablename__ = 'books'
id = Column(Integer, primary_key=True)
name = Column(String(32), index=True, nullable=False)
price=Column(Integer)

 

# 一對多關係
class Hobby(Base): # 表模型
__tablename__ = 'hobby'
id = Column(Integer, primary_key=True)
caption = Column(String(50), default='籃球')


class Person(Base):
__tablename__ = 'person'
nid = Column(Integer, primary_key=True)
name = Column(String(32), index=True, nullable=True)
# hobby指的是tablename而不是類名,uselist=False
hobby_id = Column(Integer, ForeignKey("hobby.id")) # 外鍵

# 跟數據庫無關,不會新增字段,只用於快速鏈表操作
# 類名,backref用於反向查詢
hobby = relationship('Hobby', backref='pers')
def init_db():
"""
根據類創建數據庫表
:return:
"""
engine = create_engine(
"mysql+pymysql://root:[email protected]:3306/aaa?charset=utf8",
max_overflow=0, # 超過連接池大小外最多創建的連接
pool_size=5, # 連接池大小
pool_timeout=30, # 池中沒有線程最多等待的時間,否則報錯
pool_recycle=-1 # 多久之後對線程池中的線程進行一次連接的回收(重置)
)

Base.metadata.create_all(engine)

def drop_db():
"""
根據類刪除數據庫表
:return:
"""
engine = create_engine(
"mysql+pymysql://root:[email protected]:3306/aaa?charset=utf8",
max_overflow=0, # 超過連接池大小外最多創建的連接
pool_size=5, # 連接池大小
pool_timeout=30, # 池中沒有線程最多等待的時間,否則報錯
pool_recycle=-1 # 多久之後對線程池中的線程進行一次連接的回收(重置)
)

Base.metadata.drop_all(engine)

if __name__ == '__main__':
# drop_db() # 刪除表
init_db() # 創建表模型
```

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章