sqlalchemy中Column的默认值属性


字段为日期时间类型设置默认值 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 并没有进行 设置, 表结构里面的默认值。

20201206104137582

通过上面的日志 ,我可以清晰的发现,实际上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

参考文档

stackoverflow discussion

官方文档

readthedocs 地址


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM