• 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 地址

  • 相关阅读:
    Servlet学习总结
    Tomcat学习总结1
    第44周星期日反思
    第44周星期一Tomcat学习2
    第44周星期五忙碌文档的一天
    第44周星期六好文章摘录
    laravel 5.6接入微信第三方授权登陆的主要步骤
    laravel多表登录出现路由调用错误
    cURL error 60: SSL certificate problem...
    传说中Python最难理解的点|看这完篇就够了(装饰器)
  • 原文地址:https://www.cnblogs.com/caicaizi/p/14278604.html
Copyright © 2020-2023  润新知