Как динамически создавать операторы order_by и вставлять их в запрос flasksqlalchemy - PullRequest
0 голосов
/ 23 апреля 2019

Я пытаюсь динамически создать инструкцию order_by с помощью запроса flask-sqlalchemy.

Это вызов моего метода 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 Ответ

1 голос
/ 23 апреля 2019

Я решил это, используя метод text () (как примечание @shmee в комментарии к вышеуказанному вопросу).

Я изменил тип параметра, который был передан как column_order (теперь это строка)

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

Вы также можете использовать asc или desc (восходящий или нисходящий) порядок для каждого столбца, сразу после каждого имени столбца:

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()

Вот текст () документации: https://docs.sqlalchemy.org/en/13/core/sqlelement.html#sqlalchemy.sql.expression.text

Кроме того, аргумент text.text для text () может быть передан как Python строковый аргумент, который будет рассматриваться как надежный текст SQL и отображается как дано. НЕ ПЕРЕДАВАЙТЕ НЕПРАВИЛЬНЫЙ ВХОД В ЭТОТ ПАРАМЕТР.

Это означает, что вы должны передавать только доверенную строку SQL. В моей ситуации я передаю только жестко закодированную строку. Например, если вы используете строку, полученную от пользователя вашего приложения, эта строка может содержать некоторые нежелательные SQL-инъекции.

Поэтому всегда проверяйте эту пользовательскую строку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...