Flask-Grundlegende Inhalte-Sechs

I、Flask數(shù)據(jù)關(guān)聯(lián)模型SQLAlchemy

Flask-SQLAlchemy使用起來(lái)非常有趣赚导,對(duì)于基本應(yīng)用十分容易使用赤惊,并且對(duì)于大型項(xiàng)目易于擴(kuò)展。有關(guān)完整的指南圈暗,請(qǐng)參見(jiàn)SQLAlchemyAPI文檔裕膀。

常見(jiàn)情況下對(duì)于只有一個(gè) Flask 應(yīng)用,所有您需要做的事情就是創(chuàng)建 Flask 應(yīng)用,選擇加載配置接著創(chuàng)建 SQLAlchemy 對(duì)象時(shí)候把 Flask 應(yīng)用傳遞給它作為參數(shù)智绸。

一旦創(chuàng)建瞧栗,這個(gè)對(duì)象就包含 sqlalchemysqlalchemy.orm 中的所有函數(shù)和助手。此外它還提供一個(gè)名為 Model的類迹恐,用于作為聲明模型時(shí)的 delarative 基類

普通的 SQLAlchemy 不同之處:
1. SQLAlchemy 允許您訪問(wèn)下面的東西 :
·sqlalchemysqlalchemy.orm 下所有的函數(shù)和類
·一個(gè)叫做 session的預(yù)配置范圍的會(huì)話(session)
·metadata 屬性
·engine 屬性
·SQLAlchemy.create_all()SQLAlchemy.drop_all()殴边,根據(jù)模型用來(lái)創(chuàng)建以及刪除表格的方法
· 一個(gè) Model 基類,即是一個(gè)已配置的聲明(declarative)的基礎(chǔ)(base)
2. Model 聲明基類行為類似一個(gè)常規(guī)的 Python 類锤岸,不過(guò)有個(gè)query屬性是偷,可以用來(lái)查詢模型 (ModelBaseQuery)
3. 您必須提交會(huì)話,但是沒(méi)有必要在每個(gè)請(qǐng)求后刪除它(session)蛋铆,F(xiàn)lask-SQLAlchemy 會(huì)幫您完成刪除操作刺啦。

\color{violet}{在了解以上問(wèn)題后,這一章我們將用ORM的力量?jī)?yōu)化數(shù)據(jù)庫(kù)操作磕秤。}

什么是ORM?
ORM是用來(lái)把對(duì)象模型表示的對(duì)象映射到基于SQL的關(guān)系模型數(shù)據(jù)庫(kù)結(jié)構(gòu)中去。簡(jiǎn)明點(diǎn)說(shuō)市咆,數(shù)據(jù)庫(kù)中每一行就是一個(gè)對(duì)象蒙兰。


II古毛、相關(guān)的配置字段

在上一章內(nèi),我們?cè)赿b_demo內(nèi)應(yīng)用課許多諸如app.config['SQLALCHEMY_DATABASE_URI'] = xxx的語(yǔ)句鹰椒,這些語(yǔ)句為SQLAlchemy的配置方式

那么常見(jiàn)的配置選項(xiàng)有

選項(xiàng) 說(shuō)明
SQLALCHEMY_DATABASE_URI 用于連接的數(shù)據(jù)庫(kù) URI 斤贰。例如:sqlite:////tmp/test.db 或 mysql://username:password@server/db
SQLALCHEMY_BINDS 一個(gè)映射 binds 到連接 URI 的字典殖侵。更多 binds 的信息見(jiàn) 用 Binds 操作多個(gè)數(shù)據(jù)庫(kù) 。
SQLALCHEMY_ECHO 如果設(shè)置為 Ture 楞陷, SQLAlchemy 會(huì)記錄所有 發(fā)給 stderr 的語(yǔ)句茉唉,這對(duì)調(diào)試有用。
SQLALCHEMY_RECORD_QUERIES 可以用于顯式地禁用或啟用查詢記錄艾凯。查詢記錄 在調(diào)試或測(cè)試模式自動(dòng)啟用懂傀。更多信息見(jiàn) get_debug_queries() 。
SQLALCHEMY_NATIVE_UNICODE 可以用于顯式禁用原生 unicode 支持沧竟。當(dāng)使用不合適的指定無(wú)編碼的數(shù)據(jù)庫(kù)默認(rèn)值時(shí)缚忧,這對(duì)于 一些數(shù)據(jù)庫(kù)適配器是必須的(比如 Ubuntu 上某些版本的 PostgreSQL )。
SQLALCHEMY_POOL_SIZE 數(shù)據(jù)庫(kù)連接池的大小糕非。默認(rèn)是引擎默認(rèn)值(通常 是 5 )
SQLALCHEMY_POOL_TIMEOUT 設(shè)定連接池的連接超時(shí)時(shí)間。默認(rèn)是 10 禁筏。
SQLALCHEMY_POOL_RECYCLE 多少秒后自動(dòng)回收連接衡招。這對(duì) MySQL 是必要的, 它默認(rèn)移除閑置多于 8 小時(shí)的連接州刽。注意如果 使用了 MySQL 浪箭, Flask-SQLALchemy 自動(dòng)設(shè)定這個(gè)值為 2 小時(shí)。

III匹表、常見(jiàn)數(shù)據(jù)模型字段

類型名 python中類型 說(shuō)明
Integer int 普通整數(shù)宣鄙,一般是32位
SmallInteger int 取值范圍小的整數(shù),一般是16位
BigInteger int/long 不限制精度的整數(shù)
Float float 浮點(diǎn)數(shù)
Numeric decimal.Decimal 普通整數(shù),一般是32位
String str 變長(zhǎng)字符串
Text str 變長(zhǎng)字符串敏簿,對(duì)較長(zhǎng)或不限長(zhǎng)度的字符串做了優(yōu)化
Unicode unicode 變長(zhǎng)Unicode字符串
UnicodeText unicode 變長(zhǎng)Unicode字符串惯裕,對(duì)較長(zhǎng)或不限長(zhǎng)度的字符串做了優(yōu)化
Boolean bool 布爾值
Date datetime.date 時(shí)間
Time datetime.datetime 日期和時(shí)間
LargeBinary str 二進(jìn)制文件

IV、約束字段與表間關(guān)系

由于Flask-SQLAlchemy不自動(dòng)設(shè)置表內(nèi)的字段的約束與撑刺,因此需要在設(shè)計(jì)數(shù)據(jù)字段時(shí)自行添加

那么常見(jiàn)的約束字段有

選項(xiàng)名 說(shuō)明
primary_key 如果為T(mén)rue握玛,代表表的主鍵
unique 如果為T(mén)rue,代表這列不允許出現(xiàn)重復(fù)的值
index 如果為T(mén)rue冕屯,為這列創(chuàng)建索引拂苹,提高查詢效率
nullable 如果為T(mén)rue,允許有空值浴韭,如果為False,不允許有空值
default 為這列定義默認(rèn)值
autoincrement 自增

由于不自行設(shè)計(jì)id值(與Django的一定區(qū)別)Flask-SQLAlchemy并不涉及到表間關(guān)系的自動(dòng)配置泉粉,因此需要了解表間關(guān)系聯(lián)系字段

常見(jiàn)的表間關(guān)系字段有

選項(xiàng)名 說(shuō)明
backref 在關(guān)系的另一模型中添加反向引用,用于設(shè)置外鍵名稱,在1內(nèi)查n的
primary join 明確指定兩個(gè)模型之間使用的聯(lián)結(jié)條件
uselist 如果為False舍肠,不使用列表,而使用標(biāo)量值
order_by 指定關(guān)系中記錄的排序方式
secondary 指定多對(duì)多關(guān)系中關(guān)系表的名字
secondary join 在SQLAlchemy中無(wú)法自行決定時(shí)叽躯,指定多對(duì)多關(guān)系中的二級(jí)聯(lián)結(jié)條件
lazy 指定如何加載相關(guān)記錄肌括。

lazy的可選值有

屬性 說(shuō)明
select 首次訪問(wèn)時(shí)按需加載
immediate 源對(duì)象加載后就加載
joined 加載記錄谍夭,但使用聯(lián)結(jié)
subquery 立即加載,但使用子查詢
noload 永不加載
dynamic 不加載記錄紧索,但提供加載記錄的查詢

V珠漂、查詢執(zhí)行器

執(zhí)行器 說(shuō)明
all() 以列表形式返回查詢的所有結(jié)果
first() 返回查詢的第一個(gè)結(jié)果,如果沒(méi)有結(jié)果荞彼,則返回 None
first_or_404() 返回查詢的第一個(gè)結(jié)果待笑,如果沒(méi)有結(jié)果,則終止請(qǐng)求寞缝,返回 404 錯(cuò)誤響應(yīng)
get() 返回指定主鍵對(duì)應(yīng)的行仰泻,如果沒(méi)有對(duì)應(yīng)的行,則返回 None
get_or_404() 返回指定主鍵對(duì)應(yīng)的行慎宾,如果沒(méi)找到指定的主鍵,則終止請(qǐng)求趟据,返回 404 錯(cuò)誤響應(yīng)
count() 返回查詢結(jié)果的數(shù)量
paginate() 返回一個(gè) Paginate 對(duì)象汹碱,它包含指定范圍內(nèi)的結(jié)果

VI、過(guò)濾器

過(guò)濾器 說(shuō)明
filter() 把過(guò)濾器添加到原查詢上稚新,返回一個(gè)新查詢
filter_by() 把等值過(guò)濾器添加到原查詢上跪腹,返回一個(gè)新查詢
limit 使用指定的值限定原查詢返回的結(jié)果
offset() 偏移原查詢返回的結(jié)果,返回一個(gè)新查詢
order_by() 根據(jù)指定條件對(duì)原查詢結(jié)果進(jìn)行排序屯阀,返回一個(gè)新查詢
group_by() 根據(jù)指定條件對(duì)原查詢結(jié)果進(jìn)行分組轴术,返回一個(gè)新查詢


filter_by用于查詢簡(jiǎn)單的列名,不支持比較運(yùn)算符盖袭。
比f(wàn)ilter_by的功能更強(qiáng)大彼宠,支持比較運(yùn)算符,支持or_醇蝴、in_等語(yǔ)法想罕。


VII霉涨、一個(gè)簡(jiǎn)單的建表實(shí)例

我們基于上一章中的db_demo.py的內(nèi)容展開(kāi),在每一個(gè)修改的實(shí)例內(nèi)增加一個(gè)__repr__方法楼镐,簡(jiǎn)單介紹一下__repr__:當(dāng)我們需要對(duì)一個(gè)函數(shù)中傳入某個(gè)參數(shù)后的狀態(tài)需要打包打印往枷,或者顯示在屏幕上時(shí)我們可以在這個(gè)函數(shù)內(nèi)部定義一個(gè)__repr__函數(shù)凄杯,可以通過(guò)這個(gè)函數(shù)戒突,對(duì)你想要打印的內(nèi)容進(jìn)行設(shè)置描睦。

修改db_demo.py

class Role(db.Model):
    # 定義表名
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    db.relationship('User', backref='role')

    def __repr__(self):
        return 'Role:{}'.format(self.name)


class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    email = db.Column(db.String(64), unique=True)
    password = db.Column(db.String(64), unique=True)
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

    def __repr__(self):
        return 'User:{}'.format(self.name)


VIII、一些查詢的聯(lián)系

在此前隔崎,我們修改db_demo內(nèi)的main韵丑,以用來(lái)插入一些數(shù)據(jù),當(dāng)然技潘,這種方式并非日后的常用方法千康,這里只作為一種簡(jiǎn)單的填充

if __name__ == '__main__':
    # 刪除表
    db.drop_all()
    # 創(chuàng)建表
    db.create_all()
    ro1 = Role(name='admin')
    ro2 = Role(name='user')
    db.session.add_all([ro1, ro2])
    db.session.commit()
    us1 = User(name='wang', email='wang@163.com', password='123456', role_id=ro1.id)
    us2 = User(name='zhang', email='zhang@189.com', password='201512', role_id=ro2.id)
    us3 = User(name='chen', email='chen@126.com', password='987654', role_id=ro2.id)
    us4 = User(name='zhou', email='zhou@163.com', password='456789', role_id=ro1.id)
    us5 = User(name='tang', email='tang@neuedu.com', password='158104', role_id=ro2.id)
    us6 = User(name='wu', email='wu@gmail.com', password='5623514', role_id=ro2.id)
    us7 = User(name='qian', email='qian@gmail.com', password='1543567', role_id=ro1.id)
    us8 = User(name='liu', email='liu@neuedu.com', password='867322', role_id=ro1.id)
    us9 = User(name='li', email='li@163.com', password='4526342', role_id=ro2.id)
    us10 = User(name='sun', email='sun@163.com', password='235523', role_id=ro2.id)
    db.session.add_all([us1, us2, us3, us4, us5, us6, us7, us8, us9, us10])
    db.session.commit()
    db.session.add_all([us1, us2])
    db.session.commit()
    app.run(port=5005,debug=True)

1拾弃、返回名字等于wang 的所有人

    User.query.filter_by(name='wang').all()

2、返回查詢的第一個(gè)對(duì)象

    User.query.first()

3奔坟、返回所有查詢對(duì)象

    User.query.all()

4搭盾、返回名字結(jié)尾字符為g的所有數(shù)據(jù)

    User.query.filter(User.name.endswith("g")).all()
    User.query.filter(User.name.startswith("w")).all()
    User.query.filter(User.name.contains("n")).all()
    User.query.filter(User.name.like("%n%g")).all()

5、返回user中id = 1的數(shù)據(jù)

    User.query.get(1)

6澜建、返回名字不等于wang的所有數(shù)據(jù)

    User.query.filter(not_(User.name == "wang")).all()
    User.query.filter(User.name != "wang").all()

7蝌以、返回名字不等于 wang 且 郵箱 以 163.com結(jié)尾的所有

    User.query.filter(or_(User.name != 'wang',User.email.endswith('163.com') )).all()

8跟畅、查詢名字和郵箱都以 li 開(kāi)頭的所有數(shù)據(jù)

    User.query.filter(User.name.startswith("li"), User.email.startswith("li")).all()
    User.query.filter(and_(User.name.startswith("li"), User.email.startswith("li"))).all()

9、查詢password是 123456 或者 emailneuedu.com 結(jié)尾的所有數(shù)據(jù)

    User.query.filter(or_(User.password == '123456', User.email.endswith('neuedu.com'))).all()

10奸攻、查詢id為 [1, 3, 5, 7, 9] 的用戶列表

    User.query.filter(User.id.in_([1, 3, 5, 7, 9])).all()

11、 查詢name為liu的角色數(shù)據(jù)

     User.query.filter(User.name == 'liu').all()

12睹耐、查詢所有用戶數(shù)據(jù),并以郵箱排序

    User.query.order_by(User.email.desc()).all()

13占拍、每頁(yè)3個(gè)捎迫,查詢第2頁(yè)的數(shù)據(jù)

    pn = User.query.paginate(2, 3)
    pn.items # 獲取該頁(yè)內(nèi)容
    pn.page # 獲取該頁(yè)頁(yè)碼
    pn.pages # 獲取總頁(yè)數(shù)

14窄绒、定義模型,并顯示作者名和書(shū)名
作者Author()彰导,表名 author位谋,屬性有:id,name掏父,au_book(外鍵)
書(shū)名Book()赊淑,表名 books ,屬性有:id陶缺,name饱岸,au_book

class Author(db.Model):
    __tablename__ = 'author'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    au_book = db.Column(db.Integer, db.ForeignKey('book.id'))

    def __repr__(self):
        return 'Author:{}'.format(self.name)


class Book(db.Model):
    __tablename__ = 'books'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    au_book = db.relationship('Book', backref='book')

    def __repr__(self):
        return 'Book:{}'.format(self.name)

IX、增刪改的操作

Flask-SQLAlchemy的增刪改操作可以理解為是通過(guò)與數(shù)據(jù)庫(kù)建立一個(gè)小型會(huì)話的方式進(jìn)行的蛛砰,下面介紹一下這些基于db = SQLAlchemy(app)的操作

操作 說(shuō)明
create_all() 建表操作黍衙,db.create_all()
drop_all() 刪除表操作荠诬,db.drop_all()
add_all() 插入操作位仁,db.seesion.add_all([])聂抢,插入可選擇使用list進(jìn)行批量插入
commit() 提交操作棠众,db.session.commit(),提交其語(yǔ)句以上的所有更改數(shù)據(jù)庫(kù)內(nèi)容的操作
delete() 刪除操作空盼,db.session.delete()新荤,刪除一條數(shù)據(jù)

更新操作只需要選擇需要更新的對(duì)象,修改其屬性值然后提交即可篱瞎。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末痒芝,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子校哎,更是在濱河造成了極大的恐慌瞳步,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抱怔,死亡現(xiàn)場(chǎng)離奇詭異屈留,居然都是意外死亡测蘑,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)勇蝙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)挨约,“玉大人产雹,你說(shuō)我怎么就攤上這事翁锡」菹危” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵荒适,是天一觀的道長(zhǎng)开镣。 經(jīng)常有香客問(wèn)我,道長(zhǎng)陕壹,這世上最難降的妖魔是什么树埠? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任怎憋,我火速辦了婚禮,結(jié)果婚禮上绊袋,老公的妹妹穿的比我還像新娘。我一直安慰自己皂岔,他們只是感情好展姐,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布圾笨。 她就那樣靜靜地躺著,像睡著了一般擂达。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上舒憾,一...
    開(kāi)封第一講書(shū)人閱讀 49,772評(píng)論 1 290
  • 那天镀迂,我揣著相機(jī)與錄音唤蔗,去河邊找鬼。 笑死箱季,一個(gè)胖子當(dāng)著我的面吹牛棍掐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播掘殴,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼粟誓,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鹰服!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起悲酷,我...
    開(kāi)封第一講書(shū)人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤设易,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后嚎于,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體挟冠,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡知染,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嫌吠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡凭戴,死狀恐怖炕矮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情档痪,我是刑警寧澤邢滑,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站遭垛,受9級(jí)特大地震影響操灿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜庶喜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一救鲤、第九天 我趴在偏房一處隱蔽的房頂上張望本缠。 院中可真熱鬧,春花似錦丹锹、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)颊糜。三九已至,卻和暖如春秃踩,著一層夾襖步出監(jiān)牢的瞬間衬鱼,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工憔杨, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鸟赫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓芍秆,卻偏偏與公主長(zhǎng)得像惯疙,于是被迫代替她去往敵國(guó)和親翠勉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子妖啥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348