Условное массовое обновление в Django с использованием группировки - PullRequest
0 голосов
/ 11 февраля 2019

Предположим, у меня есть список транзакций со следующим определением модели:

class Transaction(models.Model):
    amount = models.FloatField()
    client = models.ForeignKey(Client)
    date = models.DateField()
    description = models.CharField()
    invoice = models.ForeignKey(Invoice, null=True)

Теперь я хочу создать счета для каждого клиента в конце месяца.Модель счета выглядит следующим образом:

class Invoice(models.Model):
    client = models.ForeignKey(Client)
    invoice_date = models.DateField()
    invoice_number = models.CharField(unique=True)

    def amount_due(self):
        return self.transaction_set.aggregate(Sum('amount'))

def create_invoices(invoice_date):
    for client in Client.objects.all():
    transactions = Transaction.objects.filter(client=client)
    if transactions.exists():
        invoice = Invoice(client=client, number=get_invoice_number(), date=invoice_date)
            invoice.save()
            transactions.update(invoice=invoice)

Я знаю, что могу создать все счета с массовым созданием в 1 запросе с массовым созданием, но мне все равно придется установить поле счета в модели транзакций.индивидуально.

Можно ли задать поле счета всех моделей транзакций одним запросом после того, как я создал все счета?Предпочтительно при использовании ORM, но с удовольствием использую необработанный SQL, если требуется.

Я знаю, что я также могу использовать группу по клиенту в списке транзакций, чтобы получить общее количество по клиенту, но тогда отдельные записи не связаны ссчет-фактура.

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

В дополнение к ответу @Bernhard Vallant.Вы можете использовать только 3 запроса.

def create_invoices(invoice_date):
    # Maybe use Exists clause here instead of subquery, 
    # do some tests for your case if the query is slow
    clients_with_transactions = Client.objects.filter(
        id__in=Transaction.objects.values('client')
    )

    invoices = [
        Invoice(client=client, number=get_invoice_number(), date=invoice_date)
        for client in clients_with_transactions
    ]

    # With PostgreSQL Django can populate id's here
    invoices = Invoice.objects.bulk_create(invoices)

    # And now use a conditional update
    cases = [
        When(client_id=invoice.client_id, then=Value(invoice.pk))
        for invoice in invoices
    ]
    Transaction.objects.update(invoice_id=Case(*cases))
0 голосов
/ 13 февраля 2019

Можно попытаться создать запрос условного обновления , если вы можете сгенерировать сопоставление клиентов с счетами до:

from django.db.models import Case, Value, When

# generate this after creating the invoices
client_invoice_mapping = {
    # client: invoice
}

cases = [When(client_id=client.pk, then=Value(invoice.pk)) 
         for client, invoice in client_invoice_mapping.items()]

Transaction.objects.update(invoice_id=Case(*cases))

Обратите внимание, что условные запросы доступны начиная с Django 1.8.В противном случае вы можете посмотреть на создание чего-то подобного, используя сырой SQL.

...