Django 'bulk_create'与相关对象

cld4siwp  于 2022-11-26  发布在  Go
关注(0)|答案(3)|浏览(264)

我有一个Django系统,它可以定期为成千上万的客户计费。以下是我的模型:

class Invoice(models.Model):
    balance = models.DecimalField(
        max_digits=6,
        decimal_places=2,
    )

class Transaction(models.Model):
    amount = models.DecimalField(
        max_digits=6,
        decimal_places=2,
    )
    invoice = models.ForeignKey(
        Invoice,
        on_delete=models.CASCADE,
        related_name='invoices',
        null=False
    )

在运行计费时,会使用几个嵌套的for循环创建数千张发票,每张发票包含数十笔交易,这会为每个创建的记录触发一个插入操作。我可以对每张发票的交易运行bulk_create(),但这仍然会导致对bulk_create()的数千次调用。
如何批量创建数千个相关模型,以便保持关系并以最有效的方式使用数据库?
备注:

  • 我正在寻找一个原生的Django解决方案,可以在所有数据库上工作(SQLite可能例外)。
  • 我的系统在一个celery任务中运行计费,以将长时间运行的代码与活动请求分离,但我仍然关心完成一个计费周期需要多长时间。
  • 该解决方案应假定其他请求或正在运行的任务也在阅读和写入所涉及的表。
dfty9e19

dfty9e191#

您可以对所有Invoice对象执行bulk_create操作,从数据库中刷新它们,使它们都有id,为所有发票创建Transaction对象,然后用bulk_create保存它们。所有这些操作都可以在单个transaction.atomic上下文中完成。
另外,特别是对于django1.10和postrgres,看看这个answer

9gm1akwq

9gm1akwq2#

您可以使用以下方法通过两个批量创建查询来完成此操作。

new_invoices = []
new_transactions = []
for loop:
    invoice = Invoice(params)
    new_invoices.append(invoice)

    for loop: 
        transaction = Transaction(params)
        transaction.invoice = invoice
        new_transactions.append(transaction)

Invoice.objects.bulk_create(new_invoices)

for each in new_transactions:
    each.invoice_id = each.invoice.id

Transaction.objects.bulk_create(new_transactions)
pvabu6sv

pvabu6sv3#

实现此目的的另一种方法可以像下面的代码片段:

from django.utils import timezone
from django.db import transaction

new_invoices = []
new_transactions = []
for sth in sth_else:
    ...
    invoice = Invoice(params)
    new_invoices.append(invoice)

for sth in sth_else:
    ...
    new_transactions.append(transaction)

with transaction.atomic():
    other_invoice_ids = Invoice.objects.values_list('id', flat=True)
    now = timezone.now()
    Invoice.objects.bulk_create(new_invoices)

    new_invoices = Invoice.objects.exclude(id__in=other_invoice_ids).values_list('id', flat=True)
    for invoice_id in new_invoices:
                transaction = Transaction(params, invoice_id=invoice_id)
                new_transactions.append(transaction)

    Transaction.objects.bulk_create(new_transactions)

我根据社区中的另一个问题this post编写此答案。

相关问题