SQLALchemy如何将SQL语句编译为特定数据库方言

最近在一个使用fastapi+tortoise-orm的项目中,需要将orm的语句编译成特定数据库方言,但是查询了官方文档及一些资料却找不到合适的方法论😔,于是乎我就把目光放到了sqlalchemy身上,东找西找给我找着了。话不多说,请看代码。

方法1:

python 复制代码
import sqlalchemy.dialects.mysql
from sqlalchemy import Integer, String, Column
from sqlalchemy.orm import declarative_base
from sqlalchemy.sql import insert

Base = declarative_base()


class Student(Base):
    __tablename__ = 'student'

    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, index=True, comment="名称")
    age = Column(Integer, index=True, comment="年龄")


def generate_sql(instance):
    stmt = insert(instance.__class__).values(
        {c.name: getattr(instance, c.name) for c in instance.__table__.columns}
    )
    return stmt.compile(dialect=sqlalchemy.dialects.mysql.dialect(), compile_kwargs={"literal_binds": True})
python 复制代码
ikun = Student(id=1, name="ikun", age=30)
jay = Student(id=1, name="jay", age=26)
print(generate_sql(ikun)) # INSERT INTO student (id, name, age) VALUES (1, 'ikun', 30)
print(generate_sql(jay))  # INSERT INTO student (id, name, age) VALUES (1, 'jay', 26)

上面代码通过insert() 创建一个 INSERT 语句对象,然后获取模型实例的对应列的值,使用stmt.compile编译成mysql的方言。但是这个方法对于json类型的字段会编译失败,出现

sqlalchemy.exc.CompileError: No literal value renderer is available for literal value "'唱跳', 'rap', '篮球'" with datatype JSON

的错误提示。

因此,介绍下一个方法。

方法2:

python 复制代码
import sqlalchemy.dialects.mysql
from sqlalchemy import Integer, String, Column, JSON, text
from sqlalchemy.orm import declarative_base
from sqlalchemy.sql.compiler import SQLCompiler

Base = declarative_base()


class Student(Base):
    __tablename__ = 'student'

    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, index=True, comment="名称")
    age = Column(Integer, index=True, comment="年龄")
    hobby = Column(JSON, comment="爱好")


def generate_sql(instance: Student) -> SQLCompiler:
    columnsmap = {c.name: getattr(instance, c.name) for c in instance.__table__.columns}
    columns = columnsmap.keys()
    stmt = text(
        f"INSERT INTO {instance.__tablename__} ({', '.join(columns)}) VALUES ({', '.join([f":{c}" for c in columns])});"
    ).bindparams(**columnsmap)
    return stmt.compile(dialect=sqlalchemy.dialects.mysql.dialect(), compile_kwargs={"literal_binds": True})

输出:

python 复制代码
ikun = Student(id=1, name="ikun", age=30, hobby=json.dumps(["唱跳", "rap", "篮球"]))
jay = Student(id=1, name="jay", age=26, hobby=json.dumps(["唱歌", "足球"]))
print(generate_sql(ikun)) # INSERT INTO student (id, name, age, hobby) VALUES (1, 'ikun', 30, '["\\u5531\\u8df3", "rap", "\\u7bee\\u7403"]');
print(generate_sql(jay)) # INSERT INTO student (id, name, age, hobby) VALUES (1, 'jay', 26, '["\\u5531\\u6b4c", "\\u8db3\\u7403"]');

如果text() 创建原始SQL文本语句,使用参数占位符 :name, :age, :hobby,bindparams() 将实际值绑定到SQL语句中的占位符,dialect=sqlalchemy.dialects.mysql.dialect() 指定使用MySQL方言。使用这种生成也不需要考虑特殊字符转义的问题。

相关推荐
程序员-Benothing35 分钟前
MySQL 中的 MVCC 是什么?如果没有 MVCC,会有什么影响?
数据库·mysql
Zenova EdgeOS36 分钟前
工业网关心跳机制:从 Keepalive 到健康判定的工程实战
大数据·网络·数据库·边缘计算·工业网关
疯狂打码的少年39 分钟前
【数据库技术】关系完整性约束(实体/参照/用户定义)
运维·服务器·数据库·笔记
郝学胜-神的一滴1 小时前
Effective Python 条款4:字符串格式化大乱斗
开发语言·网络·python·程序人生·软件工程
派小汤1 小时前
Harmony2.2.0通过RdbStore实现通用类操作本地SQLite数据库
数据库·sql·sqlite·鸿蒙·鸿蒙系统
ynchyong2 小时前
Python 字符组合生成器:product 与 permutations 的实战对比
python·工具·字符串生产
benchmark_cc2 小时前
1000只ETF的5分钟K线如何批量获取?QuantDash分页策略与高性能Python实践
开发语言·人工智能·爬虫·python·算法·quantdash·量化数据源
sel_92 小时前
【PEFT】参数高效微调(PEFT)技术详解:从原理到 LoRA/QLoRA 实战
人工智能·python·深度学习·算法·机器学习·参数高效微调
月光船幽幽2 小时前
带刺反馈引擎:唤醒深层意图
人工智能·python
程序员-Benothing2 小时前
MySQL 中的事务隔离级别有哪些?默认的事务隔离级别是什么?为什么选择这个级别?
数据库·mysql