天天看點

sqlalchemy筆記連接配接資料庫操作資料庫

http://jzqt.github.io/2015/12/29/SQLAlchemy%E7%AC%94%E8%AE%B0/

用SQLAlchemy做ORM也有一段時間了,總結一下用過的一些地方。

連接配接資料庫

SQLAlchemy通過一個url連接配接資料庫,這個url包含了連接配接資料庫相關的資訊。

資料庫連接配接URL

以MySQL為例,url的格式是

mysql+{driver}://{username}:{password}@{host}:{port}/{name}

其中

driver

是Python的資料庫驅動,比如MySQL官方的資料庫驅動

mysql-connector-python

driver

mysqlconnector

username

是資料庫使用者名;

password

是密碼;

host

是資料庫主機;

port

是資料庫端口;

name

是資料庫名。

建立資料庫引擎,中繼資料以及會話等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
      
from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import sessionmaker

db_url = "mysql+mysqlconnector://root:@localhost:3306/test"

# 通過資料庫連接配接url建立資料庫引擎
# 如果想回顯SQLAlchemy操作資料庫的日志,設定echo=True
engine = create_engine(db_url, echo=True)

# 通過資料庫引擎綁定元資訊
metadata = MetaData(engine)

# 通過綁定資料庫引擎擷取資料庫會話類
Session = sessionmaker(bind=engine) 

# 擷取資料庫會話
session = Session()
      

一個

Session

執行個體可以了解成一個資料庫連接配接,通過它來操作資料庫;

也可以将它了解成一個容器,各種對象的執行個體存儲在其中。

資料庫連接配接池

注意:以上的連接配接資料庫方式擷取資料庫連接配接是使用預設的資料庫連接配接池的,

如果不想使用資料庫連接配接池的話可以用以下方式建立資料庫引擎。

1
2
3
4
5
      
from sqlalchemy import create_engine
from sqlalchemy.pool import NullPool 
db_url = "mysql+mysqlconnector://root:@localhost:3306/test"

engine = create_engine(db_url, poolclass=NullPool)
      

操作資料庫

聲明映射

在資料庫中定義一個資料表對應在Python代碼中則是定義一個類(也就是通常所說的Model),要維持從類到表的關系,首先就要先聲明一個映射。

1
2
3
4
      
from sqlalchemy.ext.declarative import declarative_base

# 所有繼承自`Base`的實體類都會自動映射資料表
Base = declarative_base()
      

然後就可以通過繼承

Base

類來定義映射到資料表中的類了。

注意:

declarative_base()

生成的類,該類的子類一般都必須與資料庫中的一張表對應,

如果想擴充這個基類,讓所有子類都能使用,可以用如下方法。

1
2
3
4
5
6
7
8
9
10
11
      
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class BaseModel(Base):
 
 __abstract__ = True # 這樣BaseModel類就不用對應資料庫中的表了

 # ... 擴充BaseModel類的方法或屬性等

 pass
      

定義資料表模型

現在嘗試建立一個簡單的資料表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
      
from sqlalchemy import Integer, String, Enum, Column
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Student(Base):

 __tablename__ = "tb_student" # 資料表名

 # 下面是各個字段
 id = Column(Integer(), primary_key=True) # `id`字段,整數類型,主鍵,整數類型的主鍵預設為自動增長
 name = Column(String(30), nullable=False) # `name`字段,字元串類型,最大長度30,設定為NOT NULL
 gender = Column(Enum('male', 'female')) # `gender`字段,枚舉類型

 pass
      

Integer

String

Enum

等資料類型都是SQLAlchemy定義的,會根據使用的資料庫不同而使用資料庫中對應的類型,

你也可以使用特定資料庫的特定類型,以MySQL為例。

1
      
from sqlalchemy.dialects.mysql import INTEGER, ENUM, VARCHAR, TINYINT, TEXT, BLOB, DATETIME
      

建立和删除資料表

上面的代碼隻是聲明這麼一個類

Student

映射資料表

tb_student

,建立資料表的操作需要如下代碼。

1
2
3
      
# 建立所有定義的資料表,會在資料庫中執行`CREATE TABLE ...`語句
# 已經存在的資料表不會做操作
Base.metadata.create_all(engine)
      

删除資料表也是一樣的操作,值得一提的是,未在代碼中定義的資料表和不存在的資料表是不會做删除操作的。

1
2
      
# 删除所有定義的資料表
Base.metadata.drop_all(engine)
      

資料狀态

以ORM方式來對資料庫中的資料做增删查改操作是通過

Session

執行個體來完成的,

在學習了解如何以ORM方式操作資料之前首先我們要對資料的狀态有個基本的了解。

首先在ORM中,資料庫中的資料表對應于Python中的類,而資料表中的記錄對應于類的執行個體對象。

是以,對資料表中的記錄進行增删查改在Python中實際上就是對執行個體對象的操作。

資料執行個體對象有四種狀态,分别是

  • Transient - (瞬時的)

    表示該執行個體對象不在session中,當然也沒有儲存到資料庫中,

    主鍵一般情況下為

    None

    (如果一個Persistent狀态的對象進行事務復原後雖然主鍵有值,但卻是Transient狀态)。
  • Pending - (挂起的)

    調用

    session.add()

    後,Transient狀态的對象就會變成Pending狀态的對象,這個時候它隻是在

    session

    中,

    并沒有儲存到資料庫,是以主鍵依舊為

    None

    隻有觸發了

    session.flush()

    操作才會儲存到資料庫使得主鍵有值,比如查詢操作就會觸發flush。
  • Persistent - (持久的)

    session

    和資料庫中都有對應的記錄存在,為持久狀态。
  • Detached - (遊離的)

    資料庫中可能有記錄,但是

    session

    中不存在。對這種對象的操作不會觸發任何SQL語句。

要檢視資料對象的狀态可以用如下方式

1
2
3
4
      
>>> from sqlalchemy import inspect
>>> status = inspect(data_object)
>>> status.persistent
True
      

SQLAlchemy關于資料執行個體對象狀态的官方文檔

資料的簡單操作

以下面的資料表為例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
      
from sqlalchemy import Integer, String, Enum, Column
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):

 __tablename__ = 'tb_user'

 id = Column(Integer(), primary_key=True)
 name = Column(String(30), nullable=False)
 gender = Column(Enum('male', 'famale'))

 def __repr__(self):
 return "<User(id={})>".format(self.id)

 pass
      

session

來表示資料庫會話執行個體。

查詢操作

查詢子句使用

session

.query()

方法來擷取

Query

查詢對象。

查詢對象能夠使用一些方法來對應一些查詢子句,比如

.order_by()

.limit()

.filter()

等,進階的查詢後面會專門講。

查詢對象有這麼幾種方法

.one()

.all()

.scalar()

.one_or_none()

.get()

,以及

.first()

等。

下面對這幾個方法的用法及效果做簡單解釋。

  • .all()

    傳回查詢到的所有的結果。

    這個方法比較危險的地方是,如果資料量大且沒有使用

    limit

    子句限制的話,所有的結果都會加載到記憶體中。

    它傳回的是一個清單,如果查詢不到任何結果,傳回的是空清單。

  • .first()

    傳回查詢到的第一個結果,如果沒有查詢到結果,傳回

    None

  • .scalar()

    這個方法與

    .one_or_none()

    的效果一樣。

    如果查詢到很多結果,抛出

    sqlalchemy.orm.exc.MultipleResultsFound

    異常。

    如果隻有一個結果,傳回它,沒有結果傳回

    None

  • .one()

    如果隻能查詢到一個結果,傳回它,否則抛出異常。

    沒有結果時抛

    sqlalchemy.orm.exc.NoResultFound

    ,有超過一個結果時抛

    sqlalchemy.orm.exc.MultipleResultsFound

  • .one_or_none()

    比起

    .one()

    來,差別隻是查詢不到任何結果時不再抛出異常而是傳回

    None

  • .get()

    這是個比較特殊的方法。它用于根據主鍵來傳回查詢結果,是以它有個參數就是要查詢的對象的主鍵。

    如果沒有該主鍵的結果傳回

    None

    ,否則傳回這個結果。

代碼示例

1
2
3
4
5
6
7
8
9
      
# 查詢所有的User對象
session.query(User).all()
# 查詢按照主鍵升序排序後的第一個User對象
session.query(User).order_by(User.id.asc()).first()
# 查詢指定user_id為主鍵的對象
session.query(User).get(user_id)
session.query(User).filter(User.id == user_id).scalar()
session.query(User).filter(User.id == user_id).one_or_none()
session.query(User).filter(User.id == user_id).one() # 如果查詢不到會抛出異常,前面三個查詢不到隻是傳回None
      

增加操作

删除操作

修改操作

轉載于:https://www.cnblogs.com/fengff/p/9324660.html