如何动态创建order_by语句并将其注入flask.alchemy查询

时间:2019-04-23 11:20:39

标签: python flask-sqlalchemy

我正在尝试使用flask-sqlalchemy查询动态创建order_by语句。

这是我的PurchaseOrder方法的调用:

pos = PurchaseOrder.get_all_pos(column_order=['id', 'due_date'])

column_order可以具有一列或多列,我们将其用于对查询结果进行排序。

class PurchaseOrder(PurchaseOrderDB):

    @classmethod
    def get_all_pos(cls, **kwargs):
        columns = kwargs.pop('column_order', '')
        columns_order = [getattr(cls, column) for column in columns]
        if len(columns_order) != 0:
            pos = cls.query.order_by(columns_order).all()
        else:
            pos = cls.query.all()
        return pos

columns_order是InstrumentedAttributes的列表,当我将该列表传递给order_by()方法时,我得到了预期的以下错误:

sqlalchemy.exc.ArgumentError: SQL expression object or string expected, got object of type <class 'list'> instead

因此,当我们不知道传入多少列时,还有其他方法可以动态创建order_by吗? 在这种情况下,查询应如下所示:

pos = cls.query.order_by(cls.id, cls.due_date).all()

1 个答案:

答案 0 :(得分:1)

我已经使用text()方法解决了这个问题(如上述问题注释中的@shmee注释)​​。

我已经更改了作为column_order传递的参数类型(现在是字符串)

pos = PurchaseOrder.get_all_pos(column_order='id, due_date')

您还可以在每列名称之后紧跟着对每一列使用升序或降序(升序或降序):

pos = PurchaseOrder.get_all_pos(column_order='id desc, due_date asc')

我也对我的方法进行了一些重构,所以现在可以正常工作了。

class PurchaseOrder(PurchaseOrderDB):

    @classmethod
    def get_all_pos(cls, **kwargs):
        columns_order = kwargs.pop('columns_order', '')
        if columns_order:
            return cls.query.order_by(text(columns_order)).all()
        else:
            return cls.query.all()

这是text()文档: https://docs.sqlalchemy.org/en/13/core/sqlelement.html#sqlalchemy.sql.expression.text

  

此外,text()的text.text参数可以作为Python传递   字符串参数,将被视为受信任的SQL文本和   按给定呈现。请勿将未输入的参数传递到此参数。

这意味着您只需要传递可信的SQL字符串。在我的情况下,我只传递硬编码的字符串。例如,如果您使用来自应用程序用户的字符串,则该字符串可能包含一些不需要的SQL注入。

因此,请始终验证该用户定义的字符串。