最常用的SQLAlchemy列類型

類型名 Python類型 說 明
Integer int 普通整數,一般是 32 位
SmallInteger int 取值範圍小的整數,一般是 16 位
BigInteger int 或 long 不限制精度的整數
Float float 浮點數
Numeric decimal.Decimal 定點數
String str 變長字符串
Text str 變長字符串,對較長或不限長度的字符串做了優化
Unicode unicode 變長 Unicode 字符串
UnicodeText unicode 變長 Unicode 字符串,對較長或不限長度的字符串做了優化
Boolean bool 布爾值
Date datetime.date 日期
Time datetime.time 時間
DateTime datetime.datetime 日期和時間
Interval datetime.timedelta 時間間隔
Enum str 一組字符串
PickleType 任何 Python 對象 自動使用 Pickle 序列化
LargeBinary str 二進制文件

最常使用的SQLAlchemy列選項

選項名 說 明
primary_key 如果設為 True ,這列就是表的主鍵
unique 如果設為 True ,這列不允許出現重復的值
index 如果設為 True ,為這列創建索引,提升查詢效率
nullable 如果設為 True ,這列允許使用空值;如果設為 False ,這列不允許使用空值
default 為這列定義默認值

關系表達

一對多class
class Role(db.Model):

# ...
users = db.relationship('User', backref='role')#添加到 Role 模型中的 users 屬性代表這個關系的面向對象視角。對於一個 Role 類的實例,其 users 屬性將返回與角色相關聯的用戶組成的列表。db.relationship() 的第一個參數表,如果模型類尚未定義,可使用字符串形式指定。db.relationship() 中的 backref 參數向 User 模型中添加一個 role 屬性,從而定義反向關系。這一屬性可替代 role_id 訪問 Role 模型,此時獲取的是模型對象

class User(db.Model):

# ...
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))#關系使用 users 表中的外鍵連接了兩行。添加到 User 模型中的 role_id 列被定義為外鍵,就是這個外鍵建立起了關系。傳給 db.ForeignKey() 的參數 'roles.id' 表明,這列的值是 roles 表中行的 id 值。

db.relationship() 都能自行找到關系中的外鍵,但有時卻無法決定把哪一列作為外鍵。如果 User 模型中有兩個或以上的列定義為 Role 模型的外鍵,SQLAlchemy 就不知道該使用哪列。如果無法決定外鍵,你就要為 db.relationship() 提供額外參數,從而確定所用外鍵

常用的SQLAlchemy關系選項

選項名 說 明
backref 在關系的另一個模型中添加反向引用
primaryjoin 明確指定兩個模型之間使用的聯結條件。只在模棱兩可的關系中需要指定
lazy 指定如何加載相關記錄。可選值有 select (首次訪問時按需加載)、 immediate (源對象加載後就加載)、 joined (加載記錄,但使用聯結)、 subquery (立即加載,但使用子查詢),noload (永不加載)和 dynamic (不加載記錄,但提供加載記錄的查詢)
uselist 如果設為 Fales ,不使用列表,而使用標量值
order_by 指定關系中記錄的排序方式
secondary 指定 多對多 關系中關系表的名字
secondaryjoin SQLAlchemy 無法自行決定時,指定多對多關系中的二級聯結條件
  • 一對一
    一對一關系可以用前面介紹的一對多關系表示,但調用 db.relationship() 時要把 uselist 設為 False ,把“多”變成“一”。

多對多

tags = db.Table('tags',
    db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')),
    db.Column('page_id', db.Integer, db.ForeignKey('page.id'))
)

class Page(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    tags = db.relationship('Tag', secondary=tags,
        backref=db.backref('pages', lazy='dynamic'))

class Tag(db.Model):
    id = db.Column(db.Integer, primary_key=True)

數據庫操作

創建表

python hello.py shell
from hello import db
db.create_all()

刪除表

db.drop_all()

插入行

創建對象,模型的構造函數接受的參數是使用關鍵字參數指定的模型屬性初始值。

admin_role = Role(name='Admin')
user_role = Role(name='User')
user_susan = User(username='susan', role=user_role)#role 屬性也可使用,雖然它不是真正的數據庫列,但卻是一對多關系的高級表示。
user_john = User(username='john', role=admin_role)

這些新建對象的 id 屬性並沒有明確設定,因為主鍵是由 Flask-SQLAlchemy 管理的。

print(admin_role.id)#None

通過數據庫會話管理對數據庫所做的改動,在 Flask-SQLAlchemy 中,會話由 db.session 表示。

首先,將對象添加到會話中

db.session.add(admin_role)
db.session.add(user_role)
db.session.add(user_susan)
db.session.add(user_john)

簡寫:db.session.add_all([admin_role, user_role, user_john, user_susan])

通過提交會話(事務),將對象寫入數據庫

db.session.commit()

會話提交

數據庫會話能保證數據庫的一致性。提交操作使用原子方式把會話中的對象全部寫入數據庫。如果在寫入會話的過程中發生了錯誤,整個會話都會失效。
數據庫會話也可 回滾 。調用 db.session.rollback() 後,添加到數據庫會話中的所有對象都會還原到它們在數據庫時的狀態。

修改行

admin_role.name = 'Administrator'
db.session.add(admin_role)
session.commit()

刪除行

db.session.delete(mod_role)
session.commit()

查詢行

查詢全部。Role.query.all()

條件查詢(使用過濾器)。User.query.filter_by(role=user_role).all()

user_role = Role.query.filter_by(name='User').first()#filter_by() 等過濾器在 query 對象上調用,返回一個更精確的 query 對象。

常用過濾器

過濾器 說 明
filter() 把過濾器添加到原查詢上,返回一個新查詢
filter_by() 把等值過濾器添加到原查詢上,返回一個新查詢
limit() 使用指定的值限制原查詢返回的結果數量,返回一個新查詢
offset() 偏移原查詢返回的結果,返回一個新查詢
order_by() 根據指定條件對原查詢結果進行排序,返回一個新查詢
group_by() 根據指定條件對原查詢結果進行分組,返回一個新查詢

最常使用的SQLAlchemy查詢執行函數

方 法 說 明
all() 以列表形式返回查詢的所有結果
first() 返回查詢的第一個結果,如果沒有結果,則返回 None
first_or_404() 返回查詢的第一個結果,如果沒有結果,則終止請求,返回 404 錯誤響應
get() 返回指定主鍵對應的行,如果沒有對應的行,則返回 None
get_or_404() 返回指定主鍵對應的行,如果沒找到指定的主鍵,則終止請求,返回 404 錯誤響應
count() 返回查詢結果的數量
paginate() 返回一個 Paginate 對象,它包含指定範圍內的結果
  • 關系查詢

    執行 user_role.users 表達式時,隱含的查詢會調用 all() 返回一個用戶列表。 query 對象是隱藏的,因此無法指定更精確的查詢過濾器。

users = user_role.users

修改了關系的設置,加入了 lazy = 'dynamic' 參數,從而禁止自動執行查詢

class Role(db.Model): users = db.relationship('User', backref='role', lazy='dynamic')

順序排列

user_role.users.order_by(User.username).all()

在視圖函數中操作數據庫

@app.route('/', methods=['GET', 'POST'])
def index():
    form = NameForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.name.data).first()
        if user is None:
            user = User(username = form.name.data)
            db.session.add(user)
            session['known'] = False
        else:
            session['known'] = True
        session['name'] = form.name.data
        form.name.data = http://blog.csdn.net/sun_dragon/article/details/''
        return redirect(url_for('index'))
    return render_template('index.html', form = form, name = session.get('name'), known = session.get('known', False))

修改模板

{ % extends "base.html" % }
{ % import "bootstrap/wtf.html" as wtf % }
{ % block title % }Flasky{ % endblock % }
{ % block page_content % }
    <div class="page-header">
        <h1>Hello, { % if name % }{{ name }}{ % else % }Stranger{ % endif % }!</h1>
        { % if not known % }
            <p>Pleased to meet you!</p>
        { % else % }
            <p>Happy to see you again!</p>
        { % endif % }
    </div>
    {{ wtf.quick_form(form) }}
{ % endblock % }

集成 Python shell

讓 Flask-Script 的 shell 命令自動導入特定的對象

from flask.ext.script import Shell
def make_shell_context():
    return dict(app=app, db=db, User=User, Role=Role)  
manager.add_command("shell", Shell(make_context=make_shell_context))

make_shell_context() 函數註冊了程序、數據庫實例以及模型,因此這些對象能直接導入 shell

results matching ""

    No results matching ""