使用 SQLAlchemy 处理 MySQL 上的 TIMESTAMP 类型的一点小技巧,很冷门的知识点哦。

SQLAlchemy 是一个功能强大的 ORM 。本篇介绍使用 SQLAlchemy 处理 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: ‘\nCREATE TABLE bonus (\n\tbid INTEGER NOT NULL AUTO_INCREMENT, \n\tagent BIGINT NOT NULL, \n\tmaster BIGINT NOT NULL, \n\tprice INTEGER NOT NULL DEFAULT 0, \n\tshare INTEGER NOT NULL DEFAULT 0, \n\tcreatetime TIMESTAMP NOT NULL DEFAULT NOW(), \n\tupdatetime TIMESTAMP NOT NULL, \n\tPRIMARY KEY (bid), \n\tFOREIGN KEY(agent) REFERENCES account (gameuid), \n\tFOREIGN KEY(master) REFERENCES account (gameuid)\n)\n\n’]

如果你一定要把 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: ‘\nCREATE TABLE bonus (\n\tbid INTEGER NOT NULL AUTO_INCREMENT, \n\tagent BIGINT NOT NULL, \n\tmaster BIGINT NOT NULL, \n\tprice INTEGER NOT NULL DEFAULT 0, \n\tshare INTEGER NOT NULL DEFAULT 0, \n\tupdatetime TIMESTAMP NOT NULL DEFAULT 0, \n\tcreatetime TIMESTAMP NOT NULL DEFAULT NOW(), \n\tPRIMARY KEY (bid), \n\tFOREIGN KEY(agent) REFERENCES account (gameuid), \n\tFOREIGN KEY(master) REFERENCES account (gameuid)\n)\n\n’]

参考文章

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一种 Python 的 ORM(对象关系映射)库,它提供了一种抽象层,可以用 Python 对象的方式来操作数据库。而 MySQL 全文检索(Full-Text Search)是一种用于处理自然语言的搜索技术,它可以在 MySQL 中进行配置和使用。 在 SQLAlchemy 中,我们可以使用 MySQL 的全文检索来进行高效的文本搜索。具体步骤如下: 1. 首先,我们需要在 MySQL 中创建一个支持全文检索的表。例如: ```sql CREATE TABLE products ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255), description TEXT, FULLTEXT(name, description) ) ENGINE=InnoDB; ``` 这个表包括了 id、name 和 description 三个字段,其中 name 和 description 两个字段被指定为全文检索字段。 2. 然后,在 SQLAlchemy 中定义一个对应的模型类。例如: ```python from sqlalchemy import Column, Integer, String, Text from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class Product(Base): __tablename__ = 'products' id = Column(Integer, primary_key=True) name = Column(String(255)) description = Column(Text) ``` 这个模型类对应了 MySQL 中的 products 表,并且使用 SQLAlchemy 提供的 Column 类型来定义了 id、name 和 description 三个字段。 3. 接下来,我们可以使用 SQLAlchemy 提供的 fulltext 模块来执行全文检索。例如: ```python from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base from sqlalchemy_searchable import make_searchable Base = declarative_base() engine = create_engine('mysql+pymysql://user:password@host:port/dbname?charset=utf8mb4') Session = sessionmaker(bind=engine) make_searchable() class Product(Base): __tablename__ = 'products' id = Column(Integer, primary_key=True) name = Column(String(255)) description = Column(Text) @classmethod def search(cls, query): session = Session() return session.query(cls).search(query).all() ``` 这里我们使用SQLAlchemy-Searchable 扩展,它提供了一个 make_searchable() 函数来启用全文检索功能。然后我们在模型类中定义了一个 search() 方法,它接受一个查询字符串并返回符合条件的结果。 4. 最后,我们可以使用 search() 方法来进行全文检索。例如: ```python products = Product.search('foo bar') for product in products: print(product.name, product.description) ``` 这个例子中,我们执行了一个名为 'foo bar' 的全文检索,并遍历了检索结果中的每个产品,然后打印出了产品的名称和描述。 总的来说,使用 SQLAlchemyMySQL 全文检索可以帮助我们在 Python 中高效地进行文本搜索,从而提高了应用程序的性能和用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值