Сортировать по столбцу вывода запроса - PullRequest
1 голос
/ 04 августа 2020

Я использую графен с sqlalchemy, и у меня есть выходной объект, содержащий вычисленное поле. Поле вычисляется согласно некоторому входному параметру (запросу) и более или менее выглядит так (для упрощения рассмотрим, что я вычисляю f (x) = ax + b , где a и b - оба столбца в моей таблице Thing):

import models

class Thing(SQLAlchemyObjectType):
    class Meta:
        model = models.Thing
        interfaces = (relay.Node, )

    f = graphene.Field(graphene.Float)

    def resolve_f(self, info):
        return self.a * info.context['x'] + self.b

В моем запросе у меня есть следующее, и я хотел бы отсортировать поля в соответствии с выводом функции f:

class Query(graphene.ObjectType):
    best_points = graphene.List(lambda: Thing, x = graphene.Float())

    def resolve_best_points(self, info, x):
        query = Thing.get_query(info)
        return query.all()

Сначала я пробовал выполнять сортировку внутри resolve_best_points, используя что-то вроде query.order_by("f").all(), но тщетно, поскольку графен, кажется, добавляет это поле вне резолвера (ie., query.all() содержит только a и b, но не f(a, b)).

Есть ли способ добиться этого чистым способом? Добавить какую-нибудь опцию в Thing? Или, может быть, получение выходных значений в преобразователе, а затем сортировка? Или что-то более уродливое, например, добавление промежуточного программного обеспечения для сортировки выходных данных из resolve_best_points?

Что возможно, каковы плюсы и минусы возможных решений этого?

Обратите внимание, что это несколько связанный с этим вопросом: Порядок SQLalchemy по вычисляемому столбцу , но это также совсем другое, потому что здесь мне не нужны вычисления, основанные только на полях базы данных (текущие решения не работают, когда здесь задействованы переменные, например info.context['x'] в этом игрушечном примере).

1 Ответ

0 голосов
/ 18 августа 2020

Вы можете использовать функции SQLAlchemy orm.with_expression и orm.query_expression для применения специальных c выражений к вашему запросу, а затем использовать их в предложении ORDER_BY.

Добавить атрибут query_expression к вашей модели Thing.

# models.py
from sqlalchemy import Float, Integer, orm

class Thing(Base):
    __tablename__ = 'things'
    id = Column(Integer, primary_key=True)
    a = Column(Float)
    b = Column(Float)

    expr = orm.query_expression()

Теперь вы можете использовать with_expression для передачи произвольных выражений SQL в ваши запросы. Значение атрибута expr для Thing объектов будет результатом выражения.

# schema.py
import graphene

from graphene import relay
from sqlalchemy.orm import with_expression

from models import Thing as ThingModel


class Thing(SQLAlchemyObjectType):
    class Meta:
        model = ThingModel
        interfaces = (relay.Node,)


class Query(graphene.ObjectType)
    best_points = graphene.List(Thing, x=graphene.Float())

    def resolve_best_points(self, info, x):
        expr = ThingModel.a * x + ThingModel.b

        return (
            Thing.get_query(info)
            .options(with_expression(ThingModel.expr, expr))
            .order_by(expr)
            .all()
        )

Более подробная информация и список предостережений, о которых следует помнить, находятся в этом разделе SQLAlchemy документы: время запроса SQL выражения как сопоставленные атрибуты .

...