代码之家  ›  专栏  ›  技术社区  ›  Tamás

python db-api:如何处理不同的参数样式?

  •  12
  • Tamás  · 技术社区  · 14 年前

    我正在实现一个Python本体类,该类使用数据库后端来存储和查询本体。数据库模式是固定的(预先指定),但我不知道使用的是哪种类型的数据库引擎。但是,我可以依赖这样一个事实:数据库引擎的python接口使用python db-api 2.0( PEP 249 )一个简单的想法是让用户通过符合PEP249的 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 后端模块的属性。例如,如果 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 )如果我想让我的类能够处理不同的数据库后端,似乎我必须准备好所有的参数标记样式。对于我来说,这似乎违背了通用DBAPI的全部目的,因为我不能在不同的数据库后端使用相同的参数化查询。

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

    3 回复  |  直到 11 年前
        1
  •  1
  •   Steven    14 年前

    严格地说,问题不是由允许这样做的DBAPI引起的,而是由使用不同SQL语法的不同数据库引起的。db api模块将准确的查询字符串以及参数传递给数据库。“解析“参数标记由数据库本身完成,而不是由DBAPI模块完成。

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

        2
  •  5
  •   Bruno    12 年前
    • This Python recipe 可能会有所帮助。它引入了一个额外的抽象层,将参数包装在自己的抽象层中。 Param 班级。

    • 这个 PyDal 项目也可能更接近您试图实现的目标:“ 通过pydal,可以对任何符合DBAPI2.0的模块使用相同的paramStyle和datetime类型。此外,参数样式和日期时间类型是可配置的。

        3
  •  0
  •   IcarusNM    11 年前

    我也不想通过使用 更高层次的抽象(例如,SQLAlchemy)。

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

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

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

    挑选你的毒药。