• SQLAlchemy and MySQL TIMESTAMP


    列的默认值

    注意,在使用 db.create_all() 进行初始化创建表的时候,如果为 Column 指定了 default 的值,并不会影响创建的表中的对应列的默认值。这些 default 的值仅仅是在使用 SQLAlchemy 系统插入值的时候会提供默认值。如果你希望影响 MySQL 中 Column 的默认值,必须使用 server_default 来指定。

    例如要设置一个 Colmun 默认值为0 ,则需要设定 server_default=text('0') 。

    MySQL 的默认行为

     使用下面的代码创建一个默认值不为空的 TIMESTAMP Column :

    updatetime = db.Column(db.TIMESTAMP(True), nullable=False)
    

    如果对一个 TIMESTAMP Column 使用 nullable=False ,MySQL 会自动加入on update CURRENT_TIMESTAMP 。这是 MySQL 的默认行为:sysvar_explicit_defaults_for_timestamp 。 请关注下面的 updatetime Field :

    mysql> desc bonus;
    +------------+------------+------+-----+-------------------+-----------------------------+
    | Field      | Type       | Null | Key | Default           | Extra                       |
    +------------+------------+------+-----+-------------------+-----------------------------+
    | bid        | int(11)    | NO   | PRI | NULL              | auto_increment              |
    | price      | int(11)    | NO   |     | 0                 |                             |
    | share      | int(11)    | NO   |     | 0                 |                             |
    | updatetime | timestamp  | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
    | createtime | timestamp  | NO   |     | CURRENT_TIMESTAMP |                             |
    +------------+------------+------+-----+-------------------+-----------------------------+

    然而,Extra 中包含 on update CURRENT_TIMESTAMP 的 Column, 在每次更新该 Recored 的时候,updatetime 都会自动更新。

    所以,如果需要给时间戳类型加入默认值,但不在每次更新的时候自动更新时间戳,可以这样做:

    # 条目的更新时间。每次更新条目的时候,本字段会自动更新时间戳
    updatetime = db.Column(db.TIMESTAMP(True), nullable=False)
    # 条目的创建时间。每次更新条目的时候,本字段不会自动更新时间戳
    createtime = db.Column(db.TIMESTAMP(True), nullable=False, server_default=text('NOW()'))
    # 或者
    createtime = db.Column(db.TIMESTAMP(True), nullable=False, server_default=text('CURRENT_TIMESTAMP'))

    调整默认行为的顺序

    SqlAlchemy TIMESTAMP ‘on update’ extra 中提到 on update CURRENT_TIMESTAMP 必须是第一个 TIMESTAMP 列。对这点我并不认同,经过测试,我的结论如下:

    如果你希望通过设定非空让 MySQL 自动生成 on update CURRENT_TIMESTAMP ,则 必须 将该列作为第一个 TIMESTAMP 列。

    class Bonus(db.Model):
        __tablename__ = 'bonus'
        bid = db.Column(db.INT, primary_key=True, autoincrement=True)
        # 总充值
        price = db.Column(db.INTEGER, nullable=False, server_default=text('0'))
        # 总分红
        share = db.Column(db.INTEGER, nullable=False, server_default=text('0'))
        # 更新时间
        updatetime = db.Column(db.TIMESTAMP(True), nullable=False)
        # 创建时间
        createtime = db.Column(db.TIMESTAMP(True), nullable=False, server_default=text('NOW()'))

    如果调换顺序如下:

    class Bonus(db.Model):
        __tablename__ = 'bonus'
        bid = db.Column(db.INT, primary_key=True, autoincrement=True)
        # 总充值
        price = db.Column(db.INTEGER, nullable=False, server_default=text('0'))
        # 总分红
        share = db.Column(db.INTEGER, nullable=False, server_default=text('0'))
        # 创建时间
        createtime = db.Column(db.TIMESTAMP(True), nullable=False, server_default=text('NOW()'))
        # 更新时间
        updatetime = db.Column(db.TIMESTAMP(True), nullable=False)

    会报错:

    sqlalchemy.exc.InternalError: (pymysql.err.InternalError) (1067, “Invalid default value for ‘updatetime’") [SQL: ‘ CREATE TABLE bonus ( bid INTEGER NOT NULL AUTO_INCREMENT, agent BIGINT NOT NULL, master BIGINT NOT NULL, price INTEGER NOT NULL DEFAULT 0, share INTEGER NOT NULL DEFAULT 0, createtime TIMESTAMP NOT NULL DEFAULT NOW(), updatetime TIMESTAMP NOT NULL, PRIMARY KEY (bid), FOREIGN KEY(agent) REFERENCES account (gameuid), FOREIGN KEY(master) REFERENCES account (gameuid) ) ’]

    如果你一定要把 updatetime 作为第二个 timestamp 列,可以这样做:

    class Bonus(db.Model):
        __tablename__ = 'bonus'
        bid = db.Column(db.INT, primary_key=True, autoincrement=True)
        # 总充值
        price = db.Column(db.INTEGER, nullable=False, server_default=text('0'))
        # 总分红
        share = db.Column(db.INTEGER, nullable=False, server_default=text('0'))
        # 创建时间
        createtime = db.Column(db.TIMESTAMP(True), nullable=False, server_default=text('NOW()'))
        # 更新时间
        updatetime = db.Column(db.TIMESTAMP(True), nullable=False, server_default=text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))

    效果如下:

    +------------+------------+------+-----+-------------------+-----------------------------+
    | Field      | Type       | Null | Key | Default           | Extra                       |
    +------------+------------+------+-----+-------------------+-----------------------------+
    | bid        | int(11)    | NO   | PRI | NULL              | auto_increment              |
    | agent      | bigint(20) | NO   | MUL | NULL              |                             |
    | master     | bigint(20) | NO   | MUL | NULL              |                             |
    | price      | int(11)    | NO   |     | 0                 |                             |
    | share      | int(11)    | NO   |     | 0                 |                             |
    | createtime | timestamp  | NO   |     | CURRENT_TIMESTAMP |                             |
    | updatetime | timestamp  | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
    +------------+------------+------+-----+-------------------+-----------------------------+

    使用 default

    我们也可以把默认值设置为空,然后通过 SQLAlchemy Column 提供的 default 在 python 层面自动加入默认值:

    class Bonus(db.Model):
        __tablename__ = 'bonus'
        bid = db.Column(db.INT, primary_key=True, autoincrement=True)
        # 总充值
        price = db.Column(db.INTEGER, nullable=False, server_default=text('0'))
        # 总分红
        share = db.Column(db.INTEGER, nullable=False, server_default=text('0'))
        # 创建时间
        createtime = db.Column(db.TIMESTAMP(True), nullable=False, server_default=text('NOW()'))
        # 更新时间
        updatetime = db.Column(db.TIMESTAMP(True), nullable=True, default=func.utcnow())

     效果如下。在这种情况下,MySQL 中没有设定 updatetime 的默认值,但是在给 Column 赋值的时候,python 会使用 utcnow 自动为其加入默认值。这是在 SQLAlchemy 层面实现的,并不是在 MySQL 中实现的。

    +------------+------------+------+-----+-------------------+----------------+
    | Field      | Type       | Null | Key | Default           | Extra          |
    +------------+------------+------+-----+-------------------+----------------+
    | bid        | int(11)    | NO   | PRI | NULL              | auto_increment |
    | agent      | bigint(20) | NO   | MUL | NULL              |                |
    | master     | bigint(20) | NO   | MUL | NULL              |                |
    | price      | int(11)    | NO   |     | 0                 |                |
    | share      | int(11)    | NO   |     | 0                 |                |
    | createtime | timestamp  | NO   |     | CURRENT_TIMESTAMP |                |
    | updatetime | timestamp  | YES  |     | NULL              |                |
    +------------+------------+------+-----+-------------------+----------------+

    MySQL 版本的限制

    另外,很多文章提到了 使用 server_default=text('0') 作为默认值。在 MySQL5.7上,这个默认值是不可用的:

    class Bonus(db.Model):
        __tablename__ = 'bonus'
        bid = db.Column(db.INT, primary_key=True, autoincrement=True)
        # 总充值
        price = db.Column(db.INTEGER, nullable=False, server_default=text('0'))
        # 总分红
        share = db.Column(db.INTEGER, nullable=False, server_default=text('0'))
        # 更新时间
        updatetime = db.Column(db.TIMESTAMP(True), nullable=False, server_default=text('0'))
        createtime = db.Column(db.TIMESTAMP(True), nullable=False, server_default=text('NOW()'))

    sqlalchemy.exc.InternalError: (pymysql.err.InternalError) (1067, “Invalid default value for ‘updatetime’") [SQL: ‘ CREATE TABLE bonus ( bid INTEGER NOT NULL AUTO_INCREMENT, agent BIGINT NOT NULL, master BIGINT NOT NULL, price INTEGER NOT NULL DEFAULT 0, share INTEGER NOT NULL DEFAULT 0, updatetime TIMESTAMP NOT NULL DEFAULT 0, createtime TIMESTAMP NOT NULL DEFAULT NOW(), PRIMARY KEY (bid), FOREIGN KEY(agent) REFERENCES account (gameuid), FOREIGN KEY(master) REFERENCES account (gameuid) ) ’]

  • 相关阅读:
    [leetcode] 17. 电话号码的字母组合
    C++17 Fold Expressions
    多线程----NSOperation
    CGD---1--开辟并发新线程
    彻底解决_OBJC_CLASS_$_某文件名", referenced from:问题(转)
    ios 内存使用陷阱 和imageNamed 、imageWithContentsOfFile:(转)
    (转)unbalanced calls to begin/end appearance transitions for uiviewcontroller的解决方法
    ios开发种证书
    使用CAShapeLayer与UIBezierPath画出想要的图形
    定位子字符串的位置
  • 原文地址:https://www.cnblogs.com/wangcheng9418/p/12871255.html
Copyright © 2020-2023  润新知