【问题标题】:Django: Filter object and create for million of recordsDjango:过滤对象并创建数百万条记录
【发布时间】:2020-03-26 15:54:16
【问题描述】:

get_or_create() 只是一个便利功能,但如果我需要一次性拥有(过滤器+创建)百万条记录? bulk_create 只创建对象但不过滤。我可以使用with transitionrawquery 来做到这一点是唯一的解决方案吗?

result = Model.objects.filter(field__lookup=value)[0] if not result: result = Model.objects.create(...) return result

【问题讨论】:

  • get_or_createbulk_create 在过滤方面有何不同?您能否提供一个更详细的示例,说明您在过滤器方面尝试做什么?
  • 运行get_or_create 一百万次有什么问题?需要多长时间?
  • 我只是不想得到而已。如果已经存在,我也需要更新。

标签: python django django-models django-queryset


【解决方案1】:

鉴于您提供的信息,我将在 Django 中提供可能的解决方案,而无需采用原始方法。如果您可以提供更多信息,例如您正在使用的数据库以及您正在使用的约束(例如执行时间、数据完整性/一致性等),我将更新此答案

解决方案 1

假设你使用的是最新的 Django 版本,你可以使用bulk_create,并通过ignore_conflicts=True

objects = [
    Model(field_1='Object Value 1'),
    Model(field_1='Object Value 2'),
    Model(field_1='Object Value 3'),
    Model(field_1='Object Value 1'),
]
Model.objects.bulk_create(objects, ignore_conflicts=True)

注意将此参数设置为 true 的怪癖:

在支持它的数据库上(除 Oracle 之外的所有数据库),将 ignore_conflicts 参数设置为 True 会告诉数据库忽略插入任何违反约束的行(例如重复唯一值)的失败。启用此参数将禁用在每个模型实例上设置主键(如果数据库通常支持它)。

https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.bulk_create

解决方案 2

或者,您可以使用 django.db.transaction.atomic 执行以下操作:

  1. 过滤数据库中已有的对象
  2. 通过删除从 1 返回的对象来修剪您的列表
  3. bulk_create那些没有加入数据库的
objects_to_add = []
with transaction.atomic():
     trimmed_list = filter_out_those_in_db(objects_to_add)
     Model.objects.bulk_create(trimmed_list)

请注意,当事务中的代码块正在执行时,这将锁定数据库。

原子性是数据库事务的定义属性。 atomic 允许我们创建一个代码块,在其中保证数据库的原子性。如果代码块成功完成,则将更改提交到数据库。如果出现异常,则回滚更改。

https://docs.djangoproject.com/en/dev/topics/db/transactions/#django.db.transaction.atomic

解决方案 3

如果您想保持简单并且没有其他模型/表引用回此模型,您可以执行以下操作:

  1. 过滤记录
  2. 不加选择地删除所有这些记录
  3. 插入您的列表

这与解决方案 2 非常相似,但您可能能够在数据库中一口气完成第 1 步和第 2 步,与在 python 中进行过滤相比,减少了执行时间。

解决方案 4

如果您想更新现有记录而不只是不添加重复记录,可以使用update_or_create 更新现有记录,并创建非重复记录。

概念与get_or_create 相似,您仍然需要为每个对象执行此操作,但过滤和更新部分也可以在数据库中而不是在 python 中一举完成

一种使用给定 kwargs 更新对象的便捷方法,必要时创建一个新对象。默认值是用于更新对象的 (field, value) 对的字典。默认值中的值可以是可调用的。

https://docs.djangoproject.com/en/dev/ref/models/querysets/#update-or-create

【讨论】:

  • @UmairSuraj 添加了解决方案 3 和 4。如果您可以提供您正在使用的约束(例如,它必须是快速的,它必须是原子的,它必须适用于 postgresql 等),我们也许可以找到更准确的答案
  • 它必须是快速和原子的,并且应该可以在 mysql 上运行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-14
  • 1970-01-01
  • 2012-10-21
  • 1970-01-01
  • 2019-09-16
  • 1970-01-01
  • 2023-01-31
相关资源
最近更新 更多