字段為日期時間類型設置默認值 NULL :
EntryDate = Column(DateTime,server_default=text('NULL'),nullable=True)
create_time = Column(DateTime, server_default=text('CURRENT_TIMESTAMP'))
update_time = Column(DateTime, server_default=text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))
文章目錄
我們知道 使用 sqlalchemy 定義 ORM 對象,需要給一些 字段設置一個默認值, default 屬性
類似下面的代碼.
class Person(Base): __tablename__ = 'Person' id = Column(Integer, autoincrement=True, primary_key=True) name = Column(String(length=64), comment='姓名') is_delete = Column(Integer,comment="是否刪除",default=0) def __repr__(self): return "<Person(id='%s', name='%s', mobile='%s')>" % \ (self.id, self.name, self.mobile, )
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
這樣就可以 在 session.add() , session.commit() 的時候,如果沒有提供這個字段的值,就會自動設置會0 寫入到數據庫里面。
我用這個類 創建表的時候 發現, 其實 sqlalchemy 並沒有進行 設置, 表結構里面的默認值。
通過上面的日志 ,我可以清晰的發現,實際上engine 來執行sql 是上面的建表語句,並沒有將 is_deleted 設置成 默認值。
后來發現 其實 Column 還有一個屬性,叫 server_default
這個值 才是真正可以生成表結構的時候,會設置默認值。
但是 我設置 server_default 值的時候
class Person(Base): __tablename__ = 'Person' id = Column(Integer, autoincrement=True, primary_key=True) name = Column(String(length=64), comment='姓名') # 這里設置 server_default 值 is_deleted = Column(Integer,comment="是否刪除",default=0,server_default=0) def __repr__(self): return "<Person(id='%s', name='%s', mobile='%s')>" % \ (self.id, self.name, self.mobile, )
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
之后生成表結構的時候,發現出現了一個錯誤如下:
Argument ‘arg’ is expected to be one of type '<class ‘str’>'
sqlalchemy.exc.ArgumentError: Argument 'arg' is expected to be one of type '<class 'str'>' or '<class 'sqlalchemy.sql.elements.ClauseElement'>' or '<class 'sqlalchemy.sql.elements.TextClause'>', got '<class 'int'>'
- 1
- 2
這里很明顯 說明 參數 錯誤, 我陷入了沉思? 為啥說我參數不對呢?
源碼 sqlalchemy.sql.schema.py
查看 server_default 要求傳入一個字符串類型的變量。
修改 orm 類
from sqlalchemy import Column, Integer, String, text class Person(Base): __tablename__ = 'Person' id = Column(Integer, autoincrement=True, primary_key=True) name = Column(String(length=64), comment='姓名') # 注意這里 只設置 server_default is_deleted = Column(Integer, comment="是否刪除", server_default=text('0')) def __repr__(self): return "<Person(id='%s', name='%s')>" % \ (self.id, self.name)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
執行生成 table 語句 ,發現可以正常生成表結構了,並且default 值 也默認設置好了。
好了,一切看起來 完美了。
所以 如果要想 定義orm ,生成表結構的時候,就自動生成 默認值,一定要使用 server_default
這個 字段,並且要求 這個字段為字符串類型, 可以使用 text
去 裝飾一下。
server_default vs. default 的區別
在sqlalchemy 中 定義Column 字段 可以有兩個default 相關的字段, 一個是 default
另一個是 server_default
,他們之間的區別呢?
查看源碼位置 sqlalchemy.sql.schema.py Column
這個類
default
這個屬性 ,就是默認生成orm 對象,如果某個字段沒有 傳值,就使用default 值,然后寫入到數據庫中。
server_default
這個屬性,要求是一個str, unicode 類型。 用來生成表結構的時候, 需要指定字段默認值的時候來指定的。
看一個小例子
下面以一個例子作為演示,下面我創建一個User 的model 類 , 然后 有一個字段 password 我設置一個 default 的屬性 ,然后創建一個表。
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, create_engine from sqlalchemy.orm import sessionmaker Base = declarative_base() # 創建連接對象,並使用 pymsql 引擎 conn_str = "mysql+pymysql://{user}:{pwd}@{host}:3306/{db_name}?charset=utf8mb4" connect_info = conn_str.format(user='root', pwd='123456', host='127.0.0.1', db_name='db1') engine = create_engine(connect_info, max_overflow=5) session_factory = sessionmaker() session_factory.configure(bind=engine) session = session_factory() class User(Base): __tablename__ = 'User' id = Column(Integer, autoincrement=True, primary_key=True) name = Column(String(length=64), comment='姓名') mobile = Column(String(length=64), comment='手機號') password = Column(String(length=64), comment='密碼', default='0000') def __repr__(self): return "<User(id='%s', name='%s', mobile='%s', password='%s')>" % \ (self.id, self.name, self.mobile, self.password) def create_table(): # 創建表結構 Base.metadata.create_all(engine) if __name__ == '__main__': create_table() print("create table successfully ")
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
創建完成后,我們到數據庫查看表結構 ,發現 並沒有 給password 一個默認值。
建表語句 如下:
CREATE TABLE `User` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) DEFAULT NULL COMMENT '姓名',
`mobile` varchar(64) DEFAULT NULL COMMENT '手機號',
`password` varchar(64) DEFAULT NULL COMMENT '密碼',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
User 表結構中並沒有給 password 生成一個 密碼的default 值。
下面我們使用 sqlalchemy 插入一個 user
if __name__ == '__main__': u = User(name='frank',mobile='123xxxx3456') session.add(u) session.commit() session.close()
- 1
- 2
- 3
- 4
- 5
數據庫查看 沒有任何問題,已經自動把 password 字段 填充成0000了。
這是在執行sql 的時候,當 ORM對象 沒有給某個字段賦值的時候, sqlalchemy 會查看 Column 屬性的default 是否有值,如果有值,則使用 當前值; 如果沒有值,則會默認為default值。
然后在進行執行sql ,所以就自動加上了默認值。
因此想要在表結構生成的時候 就設置默認值, 要使用 server_default
這個屬性,另外server_default的值必須是字符串。
# 正確的設置方式是 is_deleted = Column(Integer, default=0, server_default=text('0'))
- 1
- 2
如果沒有寫server_default參數,那么在代碼中新建對象往數據庫插入的時候是有一個值的,但是在數據庫里查看表結構,會發現表上並沒有給字段設置默認值。
另外server_default的值必須是字符串。
設置表的默認創建時間和更新時間
有的時候我們希望在表創建的時候,有創建 時間和更新時間。 所以 我們就可以使用 server_default
這個屬性 來生成就好了。
from sqlalchemy import TIMESTAMP, Boolean, Column, Float from sqlalchemy.ext.declarative import declarative_base base = declarative_base() class Base(base): __abstract__ = True __table_args__ = { 'mysql_engine': 'InnoDB', 'mysql_charset': 'utf8', 'extend_existing': True } id = Column(INT, primary_key=True, autoincrement=True) create_time = Column(TIMESTAMP, default=None, nullable=True, server_default=text('CURRENT_TIMESTAMP')) update_time = Column(TIMESTAMP, default=None, nullable=True, server_default=text( 'CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21