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方言。使用这种生成也不需要考虑特殊字符转义的问题。

相关推荐
卡卡卡卡罗特23 分钟前
每日mysql
数据结构·算法
chao_7891 小时前
二分查找篇——搜索旋转排序数组【LeetCode】一次二分查找
数据结构·python·算法·leetcode·二分查找
烛阴1 小时前
Python装饰器解除:如何让被装饰的函数重获自由?
前端·python
workflower1 小时前
MDSE和敏捷开发相互矛盾之处:方法论本质的冲突
数据库·软件工程·敏捷流程·极限编程
Tony小周1 小时前
实现一个点击输入框可以弹出的数字软键盘控件 qt 5.12
开发语言·数据库·qt
noravinsc2 小时前
django 一个表中包括id和parentid,如何通过parentid找到全部父爷id
python·django·sqlite
lifallen2 小时前
Paimon 原子提交实现
java·大数据·数据结构·数据库·后端·算法
ajassi20002 小时前
开源 python 应用 开发(三)python语法介绍
linux·python·开源·自动化
沉默媛2 小时前
如何安装python以及jupyter notebook
开发语言·python·jupyter
TDengine (老段)2 小时前
TDengine 数据库建模最佳实践
大数据·数据库·物联网·时序数据库·tdengine·涛思数据