【问题标题】:Efficient way to bulk insert with get_or_create() in Django (SQL, Python, Django)在 Django(SQL、Python、Django)中使用 get_or_create() 批量插入的有效方法
【发布时间】:2011-01-16 04:31:51
【问题描述】:

有没有更有效的方法来做到这一点?

for item in item_list:
    e, new = Entry.objects.get_or_create(
        field1 = item.field1,
        field2 = item.field2,
    )

【问题讨论】:

  • 在一条评论中,您说您需要模型。你还说你使用了executemany。您在使用 executemany 时是如何获得模型的?

标签: python django bulkinsert


【解决方案1】:

取决于你的目标。您可以使用manage.py 的loaddata 函数以适当的格式(JSON、XML、YAML...)加载数据。

另见this discussion。

【讨论】:

  • 现在链接失效了
【解决方案2】:

我会说没有。

但我想知道你的items 是什么类型,如果他们有field1 和field2 作为属性。看起来存在另一个表示条目的类,但不是从 models.Model 派生的。也许您可以省略这个类并立即创建Entry 实例而不是创建这些项目。

【讨论】:

    【解决方案3】:

    如果您不确定item_list 中的内容是否已经存在于您的数据库中,并且您需要模型对象,那么get_or_create 绝对是您的最佳选择。

    如果您知道这些项目不在您的数据库中,那么您会做得更好:

    for item in item_list:
        new = Entry.objects.create(
            field1 = item.field1,
            field2 = item.field2,
        )
    

    如果您不需要这些对象,则只需忽略函数调用的返回。它不会加快数据库的速度,但如果这是一个问题,它将有助于内存管理。

    如果您不确定数据是否已经在数据库中,但任一字段上都有unique=True 标志,那么数据库将强制执行唯一性,您可以捕获异常并继续。这将通过避免尝试选择现有对象来防止额外的 DB 命中。

    from django.db import IntegrityError
    
    for item in item_list:
        try:
            new = Entry.objects.create(
                field1 = item.field1,
                field2 = item.field2,
            )
        except IntegrityError:
            continue
    

    在任何一种情况下,您都可以通过手动管理事务来提高速度。 Django 将为每次保存自动创建并提交事务,但如果您知道您将在特定函数中进行大量数据库保存,则提供一些装饰器将大大提高效率。 Django 文档在解释所有这些方面做得比我在这里做得更好,但你可能需要特别注意django.db.transaction.commit_on_success

    【讨论】:

    • item_list 中的项目可能 已经存在于我的数据库中,是的,我需要模型对象。并且没有一个字段具有 unique=True 约束:'( 所以我认为 get_or_create 是要走的路。让我们去数据库吧!
    • 这不能回答问题。首先,他说他想bulk插入; “get_or_create is the way to go”没有帮助,因为 get_or_create 不进行批量插入。一次插入一个项目对于批量插入来说是错误的。最后,您不能只导致错误然后忽略它;在 Postgresql 中,除非您跳过检查点箍,否则最终会出现“事务中止”错误。
    【解决方案4】:

    您无法使用 get_or_create(甚至创建)进行体面的批量插入,并且没有 API 可以轻松做到这一点。

    如果您的表足够简单,使用原始 SQL 创建行不会太痛苦,那也不会太难;类似:

    INSERT INTO site_entry (field1, field2)
    (
             SELECT i.field1, i.field2
             FROM (VALUES %s) AS i(field1, field2)
             LEFT JOIN site_entry as existing
                     ON (existing.field1 = i.field1 AND existing.field2 = i.field2)
             WHERE existing.id IS NULL
    )
    

    其中 %s 是一个类似于 ("field1, field2"), ("field3, field4"), ("field5, field6") 的字符串,您必须自己正确创建和转义。

    【讨论】:

    • 按照我的做法,您可以在单个查询中批量插入许多(数百)行,这就是您通常希望进行批量插入的方式。
    • 是的,但我不能用 MySQL 做到这一点。似乎我找不到您提出的查询的正确 SQL 语法。
    • get 怎么样?如果运行此查询,您将如何接收模型对象?
    • 这可以通过新的批量插入来完成吗? docs.djangoproject.com/en/dev/releases/1.4/… ?
    • 这可能会有所帮助,stackoverflow.com/questions/20747117/…
    【解决方案5】:

    从 1.4 开始你可以做 bulk_create

    见the docs

    *请注意注意事项(最重要的是不会调用模型的 save() 方法,因此不会发送 pre_save 和 post_save 信号。)*

    【讨论】:

      猜你喜欢
      • 2021-09-15
      • 2016-03-03
      • 1970-01-01
      • 2011-04-16
      • 2011-05-16
      • 2013-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多