【问题标题】:Conditional bulk update in Django using grouping使用分组在 Django 中进行条件批量更新
【发布时间】:2019-07-04 16:46:28
【问题描述】:

假设我有一个具有以下模型定义的交易列表:

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。

我知道我也可以在交易列表中使用按客户分组来获取每个客户的总数,但是单个条目不会链接到发票。

【问题讨论】:

    标签: sql django postgresql django-models django-orm


    【解决方案1】:

    补充@Bernhard Valant 的答案。您只能使用 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))
    

    【讨论】:

      【解决方案2】:

      如果您之前能够生成从客户到发票的映射,您可以尝试构建conditional update query

      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 构建类似的东西。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-09-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多