国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

SQLAlchemy入門(一)

fyber / 1103人閱讀

摘要:參數(shù)表示是否檢查表已經(jīng)存在。此外,這條語(yǔ)句列出了表里的每一列,而在插入時(shí)一般是不需要指定的,可以通過方法加以限制限制后,列已經(jīng)沒有了可見方法限制了語(yǔ)句所包含的列。

環(huán)境:Ubuntu 15.10 64-bit

SQLAlchemy 是 Python 的 ORM 框架,它的理念是:數(shù)據(jù)庫(kù)的量級(jí)和性能重要于對(duì)象集合,而對(duì)象集合的抽象又重要于表和行。

安裝

直接通過 pip 安裝:

$ pip install sqlalchemy

打開 Python,測(cè)試是否安裝成功:

>>> import sqlalchemy
>>> sqlalchemy.__version__
"1.0.9"
創(chuàng)建引擎 SQLite

首先以 SQLite 為例,因?yàn)樗容^簡(jiǎn)單。

from sqlalchemy import create_engine, MetaData

engine = create_engine("sqlite:///foo.db", echo=True)
metadata = MetaData(engine)

參數(shù) sqlite:///foo.db 解釋為:

sqlite:///

其中foo.db是相對(duì)路徑。也可寫成:

sqlite:///./foo.db

SQLAlchemy 缺省使用 Python 內(nèi)建的 sqlite3 模塊來連接或創(chuàng)建 SQLite 數(shù)據(jù)庫(kù)。執(zhí)行完 create_engine 后,可以發(fā)現(xiàn)當(dāng)前目錄多了 foo.db 文件,不妨用 sqlite 打開看看。

$ sqlite3 foo.db
SQLite version 3.8.11.1 2015-07-29 20:00:57
Enter ".help" for usage hints.
sqlite> .tables

注意這里用的是 sqlite3 而非 sqlite,因?yàn)?foo.db 是經(jīng)由 Python 內(nèi)建的 sqlite3 模塊創(chuàng)建的。

MySQL

再來看看連接 MySQL 時(shí)怎么創(chuàng)建引擎。
本文后續(xù)示例全部基于 MySQL,這是與官方文檔不同的地方。
先在MySQL里創(chuàng)建一個(gè)測(cè)試數(shù)據(jù)庫(kù):sa_test,后續(xù)示例都將基于這個(gè)數(shù)據(jù)庫(kù)。

mysql> CREATE DATABASE sa_test DEFAULT CHARACTER SET UTF8;
from sqlalchemy import create_engine, MetaData

engine = create_engine("mysql+mysqldb://root:******@localhost/sa_test", echo=True)
metadata = MetaData(engine)

這里的參數(shù)看上去就比較復(fù)雜了,完整的格式為:

dialect+driver://username:password@host:port/database

這里 driver 用了 mysqldb,詳見:MySQLdb:Python 操作 MySQL 數(shù)據(jù)庫(kù)

引擎配置的詳細(xì)信息可參考官方文檔:Engine Configuration

MetaData

前面在創(chuàng)建 MetaData 時(shí)綁定了引擎:

metadata = MetaData(engine)

當(dāng)然也可以不綁定。綁定的好處是,后續(xù)很多調(diào)用 (比如 MetaData.create_all(),Table.create(),等等)就不用指定引擎了。

創(chuàng)建表

創(chuàng)建兩張表,useraddress,address 表里有一個(gè) user id 的外鍵。
注意:表名沒有像官方文檔及很多人推薦的那樣使用復(fù)數(shù)形式,個(gè)人偏好而已,詳細(xì)討論請(qǐng)見 StackOverflow 的這個(gè)問題:Table Naming Dilemma: Singular vs. Plural Names (中文版)

from sqlalchemy import create_engine, MetaData,
        Table, Column, Integer, String, ForeignKey

engine = create_engine("mysql+mysqldb://root:******@localhost/sa_test", echo=True)
metadata = MetaData(engine)
user_table = Table("user", metadata,
        Column("id", Integer, primary_key=True),
        Column("name", String(50)),
        Column("fullname", String(100))
        )

address_table = Table("address", metadata,
        Column("id", Integer, primary_key=True),
        Column("user_id", None, ForeignKey("user.id")),
        Column("email", String(128), nullable=False)
        )

metadata.create_all()

執(zhí)行完 metadata.create_all() 這一句,兩張表就創(chuàng)建好了,可以在 MySQL 里立即查看。

MetaData.create_all() 可以多次調(diào)用,不會(huì)報(bào)錯(cuò),它在內(nèi)部會(huì)檢查表是否已經(jīng)創(chuàng)建。
因?yàn)?MetaData 創(chuàng)建時(shí)已經(jīng)綁定了引擎,所以此處 create_all() 就不必再指定了,否則得寫成:

metadata.create_all(engine)

創(chuàng)建引擎時(shí),echo 參數(shù)為 True,程序運(yùn)行時(shí)便有很多調(diào)試信息打印出來。在這些調(diào)試信息中,可以看到如下兩條 MySQL的CREATE TABLE 語(yǔ)句:

CREATE TABLE user (
    id INTEGER NOT NULL AUTO_INCREMENT,
    name VARCHAR(50),
    fullname VARCHAR(100),
    PRIMARY KEY (id)
)

CREATE TABLE address (
    id INTEGER NOT NULL AUTO_INCREMENT,
    user_id INTEGER,
    email VARCHAR(128) NOT NULL,
    PRIMARY KEY (id),
    FOREIGN KEY(user_id) REFERENCES user (id)
)

除了 metadata.create_all()Table 自己也有 create 方法:

create(bind=None, checkfirst=False)

參數(shù) bind 一般就是指引擎。
參數(shù) checkfirst 表示是否檢查表已經(jīng)存在。為 True 時(shí),若表已經(jīng)存在,不報(bào)錯(cuò),只是什么也不做;為
False 時(shí),若表已經(jīng)存在,則將引發(fā)異常。
使用這個(gè)方法來創(chuàng)建這兩張表:

user_table.create(checkfirst=True)
address_table.create(checkfirst=True)

這里忽略了 bind 參數(shù),因?yàn)閯?chuàng)建 MetaData 對(duì)象時(shí)已經(jīng)綁定了引擎,而創(chuàng)建表對(duì)象時(shí)又傳入了 metadata,所以順藤摸瓜,表自己是知道引擎的。
如果調(diào)整一下表的創(chuàng)建順序,就會(huì)報(bào)錯(cuò),因?yàn)?address 表里有一個(gè) user 表的外鍵,而這時(shí)候 user 表還沒創(chuàng)建呢。所以,還是建議使用 MetaData.create_all() 吧,畢竟它也會(huì)檢查表是否已經(jīng)存在。

表的反射(Table Reflection)

表創(chuàng)建好了,一般也就不動(dòng)了。所以實(shí)際應(yīng)用時(shí),往往表都已經(jīng)存在,并不需要?jiǎng)?chuàng)建,只需把它們”導(dǎo)入”進(jìn)來即可,這時(shí)就得使用 autoload 參數(shù)。

from sqlalchemy import create_engine, MetaData, Table

engine = create_engine("mysql+mysqldb://root:******@localhost/sa_test", echo=False)
metadata = MetaData(engine)

user_table = Table("user", metadata, autoload=True)

print "user" in metadata.tables
print [c.name for c in user_table.columns]

address_table = Table("address", metadata, autoload=True)
print "address" in metadata.tables

輸出:

True
["id", "name", "fullname"]
True

如果 MetaData 沒有綁定引擎,則另需指定 autoload_with 參數(shù):

user_table = Table("user", metadata, autoload=True, autoload_with=engine)

如果被反射的表外鍵引用了另一個(gè)表,那么被引用的表也會(huì)一并被反射。比如只反射 address 表,user 表也一并被反射了。

from sqlalchemy import create_engine, MetaData, Table

engine = create_engine("mysql+mysqldb://root:******@localhost/sa_test", echo=False)
metadata = MetaData(engine)

address_table = Table("address", metadata, autoload=True)

print "user" in metadata.tables
print "address" in metadata.tables

輸出:

True
True
插入數(shù)據(jù)

插入數(shù)據(jù)之前,必須要有表對(duì)象,不管是新創(chuàng)建的,還是通過反射導(dǎo)入的。

Insert 對(duì)象

要往表里插數(shù)據(jù),先創(chuàng)建一個(gè) Insert 對(duì)象:

ins = user_table.insert()
print ins

打印這個(gè) Insert 對(duì)象,可以看到它所對(duì)應(yīng)的 SQL 語(yǔ)句:

INSERT INTO user (id, name, fullname) VALUES (%s, %s, %s)

如果連接的數(shù)據(jù)庫(kù)不是 MySQL 而是 SQLite,那輸出可能就是下面這樣:

INSERT INTO user (id, name, fullname) VALUES (?, ?, ?)

可見 SQLAlchemy 幫我們封裝了不同數(shù)據(jù)庫(kù)之間語(yǔ)法的差異。
如果 MetaData 創(chuàng)建時(shí)沒有綁定引擎,那么輸出會(huì)略有不同:

INSERT INTO "user" (id, name, fullname) VALUES (:id, :name, :fullname)

這時(shí) SQLAlchemy 還不知道具體的數(shù)據(jù)庫(kù)語(yǔ)法,表名加了引號(hào)("user"),列名也改用為:id之類一般性的格式。
此外,這條INSERT語(yǔ)句列出了 user 表里的每一列,而id在插入時(shí)一般是不需要指定的,可以通過
Insert.values() 方法加以限制:

ins = ins.values(name="adam", fullname="Adam Gu")
print ins

限制后,id 列已經(jīng)沒有了:

INSERT INTO user (name, fullname) VALUES (%s, %s)

可見 values() 方法限制了 INSERT 語(yǔ)句所包含的列。但是我們指定的 namefullname 的值并沒有打印出來,這兩個(gè)值保存在 Insert 對(duì)象里,只有等到執(zhí)行時(shí)才會(huì)用到。

執(zhí)行

我們一直在說的引擎,可以理解成一個(gè)數(shù)據(jù)庫(kù)連接對(duì)象的倉(cāng)庫(kù),通過連接對(duì)象可以往數(shù)據(jù)庫(kù)發(fā)送具體的 SQL 語(yǔ)句。調(diào)用引擎的 connect() 方法可以獲取一個(gè)連接:

conn = engine.connect()

現(xiàn)在把前面的 Insert 對(duì)象丟給它來執(zhí)行:

result = conn.execute(ins)

由調(diào)試信息可見具體的 INSERT 語(yǔ)句:

INSERT INTO user (name, fullname) VALUES (%s, %s)
("adam", "Adam Gu")
COMMIT

返回值 result 是一個(gè) ResultProxy 對(duì)象,ResultProxy 是對(duì) DB-API 中 cursor 的封裝。插入語(yǔ)句的結(jié)果并不常用,但是查詢語(yǔ)句肯定是要用到它的。
不妨在 MySQL 里看一下剛插入的數(shù)據(jù)。

mysql> select * from user;
+----+------+----------+
| id | name | fullname |
+----+------+----------+
|  1 | adam | Adam Gu  |
+----+------+----------+
1 row in set (0.00 sec)
執(zhí)行多條語(yǔ)句

還記得前面的 Insert 對(duì)象使用 values() 方法來限制列嗎?

ins = ins.values(name="adam", fullname="Adam Gu")

這種方式其實(shí)不利于 Insert 對(duì)象的復(fù)用,更好的做法是把參數(shù)通過 execute() 方法傳進(jìn)去:

ins = user_table.insert()
conn.execute(ins, name="adam", fullname="Adam Gu")

Insert 對(duì)象本身還是會(huì)包含所有列,最終 INSERT 語(yǔ)句里的列由 execute() 的參數(shù)決定。由調(diào)試信息可見具體的 INSERT 語(yǔ)句:

INSERT INTO user (name, fullname) VALUES (%s, %s)
("adam", "Adam Gu")
COMMIT

一次插入多條記錄也很簡(jiǎn)單,只要傳一個(gè)字典列表(每個(gè)字典的鍵必須一致)給 execute() 即可。

conn.execute(address_table.insert(), [
    { "user_id": 1, "email": "sprinfall@gmail.com" },
    { "user_id": 1, "email": "sprinfall@hotmail.com" },
    ])

調(diào)試信息里具體的 INSERT 語(yǔ)句:

INSERT INTO address (user_id, email) VALUES (%s, %s)
((1, "sprinfall@gmail.com"), (1, "sprinfall@hotmail.com"))
COMMIT

在 MySQL 里看一下插入的地址:

mysql> select * from address;
+----+---------+-----------------------+
| id | user_id | email                 |
+----+---------+-----------------------+
|  1 |       1 | sprinfall@gmail.com   |
|  2 |       1 | sprinfall@hotmail.com |
+----+---------+-----------------------+
2 rows in set (0.00 sec)

第一部分到此結(jié)束。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/17526.html

相關(guān)文章

  • Python-SQLAlchemy:第1節(jié):SQLAlchemy入門

    摘要:下一篇文章第節(jié)查詢條件設(shè)置是編程語(yǔ)言下的一款開源軟件。提供了工具包及對(duì)象關(guān)系映射工具,使用許可證發(fā)行。在關(guān)閉連接時(shí)會(huì)自動(dòng)進(jìn)行事務(wù)提交操作。引入多條件查詢時(shí)使用。由于上下文函數(shù)退出時(shí)會(huì)自動(dòng)提交事務(wù),所以無(wú)需顯示的調(diào)用使新增生效。 下一篇文章:Python-SQLAlchemy:第2節(jié):查詢條件設(shè)置 SQLAlchemy是Python編程語(yǔ)言下的一款開源軟件。提供了SQL工具包及對(duì)象關(guān)系...

    noONE 評(píng)論0 收藏0
  • SQLAlchemy入門

    摘要:參數(shù)表示是否檢查表已經(jīng)存在。此外,這條語(yǔ)句列出了表里的每一列,而在插入時(shí)一般是不需要指定的,可以通過方法加以限制限制后,列已經(jīng)沒有了可見方法限制了語(yǔ)句所包含的列。 環(huán)境:Ubuntu 15.10 64-bit SQLAlchemy 是 Python 的 ORM 框架,它的理念是:數(shù)據(jù)庫(kù)的量級(jí)和性能重要于對(duì)象集合,而對(duì)象集合的抽象又重要于表和行。 安裝 直接通過 pip 安裝: $ pi...

    Drinkey 評(píng)論0 收藏0
  • flask入門5-model

    摘要:的模型使用模型的原因當(dāng)項(xiàng)目越來越大的時(shí)候會(huì)出現(xiàn)很多問題原生較多重復(fù)使用率低如果你的數(shù)據(jù)庫(kù)發(fā)生了改變所有的原生就都要進(jìn)行修改寫原生的時(shí)候會(huì)有安全隱患中文件關(guān)系對(duì)象的映射使用去操作數(shù)據(jù)庫(kù)的時(shí)候不會(huì)再去寫原生的了通過把表映射成類字段為你的屬性在 Flask-SQLalchemy flask的ORM模型 使用ORM模型的原因 當(dāng)項(xiàng)目越來越大的時(shí)候 會(huì)出現(xiàn)很多問題 原生SQL較多 重復(fù)使...

    Godtoy 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<