14

我正在实现一个 Python 本体类,它使用数据库后端来存储和查询本体。数据库架构是固定的(预先指定),但我不知道使用的是什么类型的数据库引擎。但是,我可以依靠数据库引擎的 Python 接口使用 Python DB-API 2.0 ( PEP 249 ) 的事实。一个简单的想法是让用户将一个符合 PEP 249 的Connection对象传递给我的本体的构造函数,然后它将使用各种硬编码的 SQL 查询来查询数据库:

class Ontology(object):
    def __init__(self, connection):
        self.connection = connection

    def get_term(self, term_id):
        cursor = self.connection.cursor()
        query = "SELECT * FROM term WHERE id = %s"
        cursor.execute(query, (term_id, ))
        [...]

我的问题是允许不同的数据库后端在查询中支持不同的参数标记,由paramstyle后端模块的属性定义。例如 if paramstyle = 'qmark',界面支持问号样式(SELECT * FROM term WHERE id = ?);paramstyle = 'numeric'表示数字的位置样式 ( SELECT * FROM term WHERE id = :1);paramstyle = 'format'表示 ANSI C 格式字符串样式 ( SELECT * FROM term WHERE id = %s)。如果我想让我的班级能够处理不同的数据库后端,似乎我必须为所有参数标记样式做好准备。对我来说,这似乎违背了通用 DB API 的全部目的,因为我不能对不同的数据库后端使用相同的参数化查询。

有没有办法解决它,如果有,最好的方法是什么?DB API 没有指定通用转义函数的存在,我可以使用它来清理查询中的值,因此手动转义不是一种选择。我不想通过使用更高级别的抽象(例如 SQLAlchemy)向项目添加额外的依赖项。

4

4 回答 4

7
  • 这个 Python 食谱可能会有所帮助。它引入了一个额外的抽象层来将参数包装在自己的Param类中。

  • PyDal项目可能更接近您想要实现的目标:“ PyDal 使任何符合 DBAPI 2.0 的模块都可以使用相同的 paramstyle 和 datetime 类型。此外,paramstyles 和 datetime 类型是可配置的。

于 2013-03-03T13:41:08.760 回答
2

严格来说,问题不是由允许这样做的 DB API 引起的,而是由使用不同 SQL 语法的不同数据库引起的。DB API 模块将确切的查询字符串与参数一起传递给数据库。“解析”参数标记由数据库本身完成,而不是由 DB API 模块完成。

这意味着如果你想解决这个问题,你必须引入一些更高层次的抽象。如果您不想添加额外的依赖项,则必须自己做。但是,您可以尝试根据后端模块的 paramstyle 将查询字符串中的参数标记动态替换为所需的参数标记,而不是手动转义和替换。然后将带有参数标记的字符串传递给数据库。例如,您可以在任何地方使用 '%s',并使用 python 字符串替换将 '%s' 替换为 ':1'、':2' 等,如果 db 使用 'numeric' 样式等等。 ..

于 2010-09-30T11:47:49.690 回答
1

让我感到困惑的是,如果您的代码只是被传递一个连接或游标对象,如何确定需要什么 paramstyle。这是我想出的:

import importlib

def get_paramstyle(conn):
    name = conn.__class__.__module__.split('.')[0]
    mod = importlib.import_module(name)
    return mod.paramstyle

您可能应该对 conn 对象进行更多的完整性检查,或者至少将其包装在一个try块中,具体取决于您愿意做出的假设。

于 2019-05-01T02:11:51.497 回答
0

我不想通过使用更高级别的抽象(例如 SQLAlchemy)向项目添加额外的依赖项。

这太糟糕了,因为 SQLAlchemy 将是解决这个问题的完美解决方案。理论上,DB-API 2.0 旨在提供这种灵活性。但这需要每个驱动程序开发人员(对于 Oracle、MySQLdb、Postgres 等)在其驱动程序中实现所有不同的参数样式。他们没有。因此,您会陷入每个数据库引擎的“首选”参数样式中。

如果您拒绝使用 SQLAlchemy 或任何其他更高的抽象层或现代 MVC 类库,是的,您必须为此编写自己的更高级别的抽象。我不建议这样做,尽管这是您在这里选择的解决方案。您在那里面临一些可怕的细节,并且会浪费时间找出其他人已经解决的错误。

不要将外部库依赖视为一件坏事。如果这是您使用 Python 的方法,那么您将错过该语言的一些最强大的功能。

选择你的毒药。

于 2014-04-22T20:16:53.843 回答