91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

數據庫操作必讀:SQLAlchemy入門

發布時間:2020-08-11 12:44:26 來源:ITPUB博客 閱讀:233 作者:大禹編程 欄目:MySQL數據庫

全文約 7991 字,讀完可能需要 12 分鐘。

環境 :Ubuntu 15.10 64-bit

SQLAlchemy是Python的ORM框架,它的理念是:數據庫的量級和性能重要于對象集合,而對象集合的抽象又重要于表和行。

安裝

直接通過pip安裝:

$ pip install sqlalchemy

打開Python,測試是否安裝成功:

>>> import sqlalchemy>>> sqlalchemy.__version__'1.0.9'

創建引擎

SQLite

首先以SQLite為例,因為它比較簡單。

from sqlalchemy import create_engine, MetaDataengine = create_engine('sqlite:///foo.db', echo=True)metadata = MetaData(engine)

參數 sqlite:///foo.db 解釋為:

sqlite://<nohostname>/<path>

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

sqlite:///./foo.db

SQLAlchemy缺省使用Python內建的sqlite3模塊來連接或創建SQLite數據庫。執行完create_engine后,可以發現當前目錄多了foo.db文件,不妨用sqlite打開看看。

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

注意這里用的是sqlite3而非sqlite,因為foo.db是經由Python內建的sqlite3模塊創建的。

MySQL

再來看看連接MySQL時怎么創建引擎。 本文后續示例全部基于MySQL,這是與官方文檔不同的地方。 先在MySQL里創建一個測試數據庫:sa_test,后續示例都將基于這個數據庫。

mysql> CREATE DATABASE sa_test DEFAULT CHARACTER SET UTF8;
from sqlalchemy import create_engine, MetaDataengine = create_engine('mysql+mysqldb://root:******@localhost/sa_test', echo=True)metadata = MetaData(engine)

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

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

這里driver用了mysqldb,詳見: MySQLdb:Python操作MySQL數據庫

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

MetaData

前面在創建MetaData時綁定了引擎:

metadata = MetaData(engine)

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

創建表

創建兩張表,user和address,address表里有一個user id的外鍵。 注意:表名沒有像官方文檔及很多人推薦的那樣使用復數形式,個人偏好而已,詳細討論請見StackOverflow的這個問題: Table NamingDilemma: Singular vs. Plural Names

from sqlalchemy import create_engine, MetaData,        Table, Column, Integer, String, ForeignKeyengine = 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()

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

MetaData.create all()可以多次調用,不會報錯,它在內部會檢查表是否已經創建。 因為MetaData創建時已經綁定了引擎,所以此處create all()就不必再指定了,否則得寫成:

metadata.create_all(engine)

創建引擎時,echo參數為True,程序運行時便有很多調試信息打印出來。在這些調試信息中,可以看到如下兩條MySQL的CREATE TABLE語句:

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)

參數bind一般就是指引擎。 參數checkfirst表示是否檢查表已經存在。為True時,若表已經存在,不報錯,只是什么也不做;為False時,若表已經存在,則將引發異常。 使用這個方法來創建這兩張表:

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

這里忽略了bind參數,因為創建MetaData對象時已經綁定了引擎,而創建表對象時又傳入了metadata,所以順藤摸瓜,表自己是知道引擎的。 如果調整一下表的創建順序,就會報錯,因為address表里有一個user表的外鍵,而這時候user表還沒創建呢。所以,還是建議使用MetaData.create_all()吧,畢竟它也會檢查表是否已經存在。

表的反射 Table Reflection

表創建好了,一般也就不動了。所以實際應用時,往往表都已經存在,并不需要創建,只需把它們"導入"進來即可,這時就得使用autoload參數。

from sqlalchemy import create_engine, MetaData, Tableengine = create_engine('mysql+mysqldb://root:******@localhost/sa_test', echo=False)metadata = MetaData(engine)user_table = Table('user', metadata, autoload=True)print 'user' in metadata.tablesprint [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參數:

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

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

from sqlalchemy import create_engine, MetaData, Tableengine = create_engine('mysql+mysqldb://root:******@localhost/sa_test', echo=False)metadata = MetaData(engine)address_table = Table('address', metadata, autoload=True)print 'user' in metadata.tablesprint 'address' in metadata.tables

輸出:

TrueTrue

插入數據

插入數據之前,必須要有表對象,不管是新創建的,還是通過反射導入的。

Insert對象

要往表里插數據,先創建一個Insert對象:

ins = user_table.insert()print ins

打印這個Insert對象,可以看到它所對應的SQL語句:

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

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

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

可見SQLAlchemy幫我們封裝了不同數據庫之間語法的差異。 如果MetaData創建時沒有綁定引擎,那么輸出會略有不同:

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

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

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

限制后,id列已經沒有了:

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

可見values()方法限制了INSERT語句所包含的列。但是我們指定的name和fullname的值并沒有打印出來,這兩個值保存在Insert對象里,只有等到執行時才會用到。

執行

我們一直在說的引擎,可以理解成一個數據庫連接對象的倉庫,通過連接對象可以往數據庫發送具體的SQL語句。調用引擎的connect()方法可以獲取一個連接:

conn = engine.connect()

現在把前面的Insert對象丟給它來執行:

result = conn.execute(ins)

由調試信息可見具體的INSERT語句:

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

返回值result是一個ResultProxy對象,ResultProxy是對DB- API中cursor的封裝。插入語句的結果并不常用,但是查詢語句肯定是要用到它的。 不妨在MySQL里看一下剛插入的數據。

mysql> select * from user;+----+------+----------+| id | name | fullname |+----+------+----------+|  1 | adam | Adam Gu  |+----+------+----------+1 row in set (0.00 sec)

執行多條語句

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

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

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

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

Insert對象本身還是會包含所有列,最終INSERT語句里的列由execute()的參數決定。由調試信息可見具體的INSERT語句:

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

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

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

調試信息里具體的INSERT語句:

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)
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

大关县| 运城市| 东阿县| 仪征市| 祁东县| 泗阳县| 大姚县| 比如县| 漳浦县| 和田县| 伊宁市| 金寨县| 临桂县| 体育| 准格尔旗| 徐水县| 东源县| 延安市| 永靖县| 航空| 靖江市| 唐河县| 永川市| 镇原县| 元氏县| 浑源县| 泾川县| 广安市| 内乡县| 乌拉特中旗| 琼中| 亚东县| 惠水县| 十堰市| 朝阳县| 临沧市| 江都市| 昂仁县| 张家港市| 宝鸡市| 汤原县|