字段为日期时间类型设置默认值 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