Django подзапрос с заполнителем - PullRequest
0 голосов
/ 30 апреля 2019

У меня есть две модели с именами User и Transaction. Здесь я хочу получить всех пользователей с общей суммой транзакции, где статус успешен.

Я пытался с подзапросом, но я не понимаю, как аннотировать совокупность подзапроса с условиями

class User(models.Model):
  name = models.CharField(max_length=128)

class Transaction(models.Model):
  user = models.ForeignKey(User)
  status = models.CharField(choices=(("success", "Success"),("failed", "Failed")))
   amount = models.DecimalField(max_digits=10, decimal_places=2)

subquery = Transaction.objects.filter(status="success", user=OuterRef('pk')).aggregate(total_spent = Coalesce(Sum('amount'), 0))

query = User.objects.annotate(total_spent=Subquery(subquery:how to do here ?)).order_by(how to order here by total_spent)

Ответы [ 3 ]

0 голосов
/ 30 апреля 2019

Вы можете нажать на этот запрос:

from django.db.models import Avg, Count, Min, Sum

User.objects.filter(status="success").annotate(total_amount=Sum('transaction__amount'))
0 голосов
/ 14 мая 2019

Это намного проще с пакетом django-sql-utils .

from django.db.models import Sum,
from sql_util.utils import SubqueryAggregate

User.objects.annotate(
    total_spend=SubqueryAggregate('transaction__amount',
                                  filter=Q(status='success'),
                                  aggregate=Sum)
)

Если вы хотите сделать это долго (без django-sql-utils), вам нужно знать эти две вещи о подзапросе:

  1. Его нельзя оценить до того, как он будет использован

  2. Может быть возвращен толькоодна запись с одним столбцом

Таким образом, вы не можете вызвать aggregate в подзапросе, потому что это сразу оценивает подзапрос.Вместо этого вы должны аннотировать значение.Вам также нужно сгруппировать по внешнему значению ref, иначе вы просто аннотируете каждую транзакцию независимо.

subquery = Transaction.objects.filter(
        status='success', user=OuterRef('pk')
    ).values(
        'user__pk'
    ).annotate(
        total_spend=Sum('amount')
    ).values(
        'total_spend'
    )

Первая .values вызывает правильную группировку по.Второй .values вызывает выбор одного значения, которое вы хотите.

0 голосов
/ 30 апреля 2019

Для использования подзапроса используйте это:

query=User.objects.annotate(total_spent=Subquery(subquery.values("user")[:1])).order_by("total_spent")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...