使用Django ORM的bulk_create函数创建后如何高效地获取对象?

问题描述 投票:0回答:3

我必须在表中插入多个对象,有两种方法可以做到这一点-

1) 使用

save()
插入每一个。但在这种情况下,将会有 n 个对象的 n sql dB 查询。

2) 使用

bulk_create()
将它们全部插入在一起。在这种情况下,将对 n 个对象进行 one sql dB 查询。

显然,第二种选择更好,因此我正在使用它。现在

bulk__create
的问题是它不会返回插入对象的 ids,因此它们不能进一步用于创建具有所创建对象的外键的其他模型的对象。

为了克服这个问题,我们需要获取由

bulk_create
创建的对象。

现在的问题是“假设在我的情况下,没有办法唯一标识创建的对象,我们如何获取它们?”

目前我正在维护一个时间戳来获取它们,如下所示-

my_objects = []

# Timestamp to be used for fetching created objects
time_stamp = datetime.datetime.now()

# Creating list of intantiated objects
for obj_data in obj_data_list:
    my_objects.append(MyModel(**obj_data))

# Bulk inserting the instantiated objects to dB
MyModel.objects.bulk_create(my_objects)

# Using timestamp to fetch the created objects
MyModel.objects.filter(created_at__gte=time_stamp)

现在效果很好,但在一种情况下会失败。

  • 如果在批量创建这些对象时,从其他地方创建了更多对象,那么这些对象也将在我的查询中获取,这是不希望的。

有人能想出更好的解决方案吗?

python django database django-models orm
3个回答
2
投票

由于

bulk_create
不会创建主键,因此您必须自己提供键。

如果您不使用默认生成的主键(

AutoField
),此过程很简单。

如果您坚持使用默认值,则需要将代码包装到原子事务中并自己提供主键。这样您就会知道插入了哪些记录。

from django.db import transaction

inserted_ids = []

with transacation.atomic():
   my_objects = []
   max_id = int(MyModel.objects.latest('pk').pk)
   id_count = max_id
   for obj_data in obj_data_list:
       id_count += 1
       obj_data['id'] = id_count
       inserted_ids.append(obj_data['id'])
       my_objects.append(MyModel(**obj_data))
   MyModel.objects.bulk_create(my_objects)
   inserted_ids = range(max_id, id_count)

0
投票

正如你所知。

如果模型的主键是 AutoField,则它不会检索并 设置主键属性,如 save() 所做的那样。

你尝试做的事,通常也是人们做的事。
某些情况下的另一种解决方案,这种方式更好。

my_ids = MyModel.objects.values_list('id', flat=True)
objs = MyModel.objects.bulk_create(my_objects)

new_objs = MyModel.objects.exclude(id__in=my_ids).values_list('id', flat=True)

0
投票

bulk_create
返回创建的对象,因此不需要重新查询数据库来查找创建的对象。

...

# Bulk inserting the instantiated objects to dB
created_objects = MyModel.objects.bulk_create(my_objects)
© www.soinside.com 2019 - 2024. All rights reserved.