前言:該筆記是本人學(xué)習(xí)SQLAlchemy官方文檔整理得來(lái)。
查看SQLAlchemy版本
>>> import sqlalchemy
>>> sqlalchemy.__version__
'1.0.15'
>>>
連接數(shù)據(jù)庫(kù)
本教程中我們將使用postgresql數(shù)據(jù)庫(kù),連接數(shù)據(jù)庫(kù)我們使用create_engine():
>>> >>> from sqlalchemy import create_engine
>>> engine = create_engine('postgresql://ricky:passwd@localhost/my_db', echo=True)
關(guān)于SQLAlchemy連接不同的數(shù)據(jù)庫(kù)的URL設(shè)置,請(qǐng)自行搜索。
echo參數(shù)是設(shè)置SQLAlchemy日志顯示的快捷方式,這樣我們?cè)趐ython命令行中執(zhí)行的命令都會(huì)在下面顯示出日志信息(這里我們能清楚看到只想的SQL語(yǔ)句詳細(xì)內(nèi)容)。如果我們不想看見(jiàn)執(zhí)行的詳細(xì)過(guò)程,可以將echo設(shè)置為False。
create_engine()函數(shù)返回一個(gè)Engin的實(shí)例,代表著訪問(wèn)數(shù)據(jù)庫(kù)的接口。
延遲連接
當(dāng)create_engine()第一次調(diào)用,它沒(méi)有嘗試去連接數(shù)據(jù)庫(kù),僅僅是當(dāng)我們執(zhí)行數(shù)據(jù)庫(kù)操作時(shí),才會(huì)去連接數(shù)據(jù)庫(kù)。
定義映射
當(dāng)我們?cè)谑褂?code>ORM的時(shí)候,數(shù)據(jù)庫(kù)中的一張表對(duì)應(yīng)著我們的一個(gè)類(lèi),我們使用declarative_base()創(chuàng)建一個(gè)基類(lèi)。
>>> from sqlalchemy.ext.declarative import declarative_base
>>> Base = declarative_base()
現(xiàn)在我們有了一個(gè)基類(lèi)Base,我們可以定義很多映射的類(lèi),先從一張完整的表格,名字為Users開(kāi)始,一個(gè)新的User類(lèi)將會(huì)映射到我們的那種表格上,在類(lèi)中我們定義關(guān)于表格的詳細(xì)信息。主要是表名、列名和數(shù)據(jù)類(lèi)型。
>>> from sqlalchemy import Column, Integer, String
>>> class User(Base):
... __tablename__ = 'users'
...
... id = Column(Integer, primary_key=True)
... name = Column(String)
... fullname = Column(String)
... password = Column(String)
...
... def __repr__(self):
... return "<User(naem=%s, fullname=%s, password=%s)>" % (self.name, self.fullname, self.password)
...
一個(gè)最簡(jiǎn)單的類(lèi)需要一個(gè)__tablename__屬性,和至少一行Column和一個(gè)外鍵primary key。
Tip######
User類(lèi)定義了一個(gè)__repr__()方法,但是這個(gè)是可選的,我們?cè)谶@里定義是為了打印出類(lèi)的對(duì)象的內(nèi)容。
創(chuàng)建一個(gè)模型
通過(guò)聲明系統(tǒng),我們已經(jīng)定義了我們表格的詳細(xì)信息,我們可以通過(guò)__table__屬性來(lái)看我們定義的類(lèi)
>>> User.__table__
Table('users', MetaData(bind=None),
Column('id', Integer(), table=<users>, primary_key=True, nullable=False),
Column('name', String(), table=<users>),
Column('fullname', String(), table=<users>),
Column('password', String(), table=<users>), schema=None)
當(dāng)我們定義了我們的類(lèi),聲明系統(tǒng)使用一個(gè)Python的metaclass來(lái)執(zhí)行其他任務(wù),一旦這個(gè)類(lèi)聲明完成。
表的對(duì)象是一個(gè)更大的稱為元數(shù)據(jù)集合的一個(gè)成員。當(dāng)我們使用這個(gè)系統(tǒng),可以使用這個(gè)對(duì)象.metadata屬性聲明我們基類(lèi)的屬性。
MetaData是一個(gè)注冊(cè)表,當(dāng)我們的數(shù)據(jù)庫(kù)不存在一個(gè)users表格,我們可以使用MetaData去創(chuàng)建一個(gè)不存在的表格,我們調(diào)用MetaData.create_all()方法,Engine作為一個(gè)數(shù)據(jù)庫(kù)的連接。
>>> Base.metadata.create_all(engine)
SELECT ...
PRAGMA table_info("users")
()
CREATE TABLE users (
id INTEGER NOT NULL, name VARCHAR,
fullname VARCHAR,
password VARCHAR,
PRIMARY KEY (id)
)
()
COMMIT
Minimal Table Descriptions vs. Full Descriptions
在上面的聲明一個(gè)表中的列時(shí),我們注意到列的數(shù)據(jù)類(lèi)型為字符串,但是沒(méi)有指定長(zhǎng)度;在SQLite和PostgreSQL中這樣的聲明是合法的,但是在其他的數(shù)據(jù)庫(kù)中是不允許的。所以,如果運(yùn)行這個(gè)教程在洽談的數(shù)據(jù)庫(kù)中,可能會(huì)報(bào)錯(cuò)。最好我很使用下面的聲明方式。
Column(String(50))
另外在Firebird和Oracle數(shù)據(jù)庫(kù)中要求sequences去生成一個(gè)新的外鍵約束。你可以使用序列來(lái)構(gòu)造。
from sqlalchemy import Sequence
Column(Integer, Sequence('user_id_seq'), primary_key=True)
完整的Table的定義為:
class User(Base):
__tablename__ = 'users'
id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
name = Column(String(50))
fullname = Column(String(50))
password = Column(String(12))
def __repr__(self):
return "<User(name='%s', fullname='%s', password='%s')>" % (
self.name, self.fullname, self.password)
創(chuàng)建一個(gè)映射的類(lèi)的對(duì)象
我們來(lái)創(chuàng)建一個(gè)User的對(duì)象.
>>> ed_user = User(name='ricky', fullname='yuziyong', password='123')
>>> ed_user.name
'ricky'
>>> ed_user.password
'123'
>>> ed_user.fullname
'yuziyong'
>>> str(ed_user.id)
'None'
盡管我們沒(méi)有特別在構(gòu)造函數(shù)指定,但是id屬性仍然產(chǎn)生了一個(gè)值None,當(dāng)我們?cè)L問(wèn)它,SQLAlchemy的工具通常會(huì)產(chǎn)生一個(gè)默認(rèn)值。