Ошибка c порядок сортировки для выражения суммы hybrid_property в Flask -Admin с использованием SQLAlchemy - PullRequest
1 голос
/ 27 февраля 2020

Учитывая следующие модели, я хотел бы добавить сортируемый столбец к Flask Admin, который показывает все предстоящие платежи для Organisation:

organisation_payments = db.Table(
    'organisation_payments',
    db.Column('payment_id', MyUUID(), db.ForeignKey('payment.id')),
    db.Column('organisation_id', MyUUID(), db.ForeignKey('organisation.id'))
)

class Organisation(db.Model):
    id = Column(ModelUUID(), primary_key=True)

    @hybrid_property
    def upcoming_payments(self):
        payments = Payment.query.filter(
            Payment.organisations.any(id=self.id),
            Payment.status == 'active'
        ).all()

        return sum([payment.amount for payment in payments])

    @upcoming_payments.expression
    def upcoming_payments(cls):
        return select([
            func.sum(Payment.amount)
        ]).where(and_(
            organisation_payments.c.organisation_id == cls.id,
            Payment.status == 'active'
        )).label('upcoming_payments')

class Payment(db.Model):
    id = Column(ModelUUID(), primary_key=True)
    amount = db.Column(db.Integer())
    status = db.Column(db.Unicode(255), default='active')
    organisations = db.relationship(
        'Organisation',
        secondary=organisation_payments,
        backref=db.backref('payments', lazy='dynamic')
    )

Обратите внимание, что теоретически Payment может быть отображается на несколько Organisation с, следовательно, отношение многих ко многим.

Я добавил upcoming_payments к column_sortable_list в Flask -Admin ModelView, но при сортировке по этому столбцу результаты ошибочны c: https://i.stack.imgur.com/VxrAE.png

Это самая минимальная версия кода, но я также пытался:

  1. используя coalesce для принудительного 0 для строк без предстоящих платежей
  2. с использованием as_scalar() вместо .label()
  3. Payment.organisations.any(id=cls.id) вместо organisation_payments.c.organisation_id == cls.id (это привело к еще большему сбивающие с толку и противоречивые результаты, и сортировка asc / desc не имела значения)

Значения, возвращаемые из обычного hybrid_property , являются правильными, как и результат, если Я запускаю это в оболочке:

stmt = select([
        func.sum(Payment.amount)
    ]).where(and_(
        Payment.organisations.any(id=org.id),
        Payment.status == 'active',
    ))

res = db.engine.execute(stmt)
res.fetchone() 
(4036200L,)

Однако результат будет крайне неточным, если я запускаю это:

stmt = select([
        func.sum(Payment.amount)
    ]).where(and_(
        organisation_payments.c.organisation_id == org.id,
        Payment.status == 'active',
    ))

res = db.engine.execute(stmt)
res.fetchone() 
(1204440000L,)

Но ни то, ни другое any() или метод таблицы ассоциации возвращает правильный порядок сортировки в Flask -Admin. Что я здесь не так делаю? Я чувствую, что, должно быть, мне не хватает distinct или подзапроса, но я в замешательстве.

ОБНОВЛЕНИЕ: Все, спасибо Илья Эвериле за то, что он направил меня к ответу:

    @upcoming_payments.expression
    def upcoming_payments(cls):
        q = select([coalesce(func.sum(Payment.amount), 0)])
        q = q.where(and_(
            organisation_payments.c.charity_id == cls.id,
            Payment.status == 'active',
            Payment.deleted.isnot(True)
        ))

        j = Payment.__table__.join(organisation_payments)
        q = q.select_from(j)

        return q.label('upcoming_donations')

1 Ответ

2 голосов
/ 27 февраля 2020

ОБНОВЛЕНИЕ: Спасибо Илья Эвериле за помощь в ответе:

    @upcoming_payments.expression
    def upcoming_payments(cls):
        q = select([coalesce(func.sum(Payment.amount), 0)])
        q = q.where(and_(
            organisation_payments.c.charity_id == cls.id,
            Payment.status == 'active',
            Payment.deleted.isnot(True)
        ))

        j = Payment.__table__.join(organisation_payments)
        q = q.select_from(j)

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