如何获得使用django bulk_create创build的对象的主键

有没有办法使用django 1.4+中的bulk_createfunction来获取您创build的项目的主键?

2016

Django 1.10 – 现在支持 (仅在Postgres上!)这里是一个链接到文档 。

>>> list_of_objects = Entry.objects.bulk_create([ ... Entry(headline="Django 1.0 Released"), ... Entry(headline="Django 1.1 Announced"), ... Entry(headline="Breaking: Django is awesome") ... ]) >>> list_of_objects[0].id 1 

从更改日志中:

在Django 1.10中进行了更改:在使用PostgreSQL时添加了对使用bulk_create()创build的对象的主键的支持

根据文件,你不能这样做: https : //docs.djangoproject.com/en/dev/ref/models/querysets/#bulk-create

批量创build只是为了:以一种有效的方式创build大量的对象,节省了大量的查询。 但这意味着你得到的回应是不完整的。 如果你这样做:

 >>> categories = Category.objects.bulk_create([ Category(titel="Python", user=user), Category(titel="Django", user=user), Category(titel="HTML5", user=user), ]) >>> [x.pk for x in categories] [None, None, None] 

这并不意味着你的类别没有pk,只是查询没有检索到它们(如果键是一个AutoField )。 如果因为某些原因需要使用pks,则需要以经典的方式保存对象。

我能想到的两种方法:

a)你可以做

 category_ids = Category.objects.values_list('id', flat=True) categories = Category.objects.bulk_create([ Category(title="title1", user=user, created_at=now), Category(title="title2", user=user, created_at=now), Category(title="title3", user=user, created_at=now), ]) new_categories_ids = Category.objects.exclude(id__in=category_ids).values_list('id', flat=True) 

如果查询集非常大,这可能会有点贵。

b)如果模型有一个created_at字段,

 now = datetime.datetime.now() categories = Category.objects.bulk_create([ Category(title="title1", user=user, created_at=now), Category(title="title2", user=user, created_at=now), Category(title="title3", user=user, created_at=now), ]) new_cats = Category.objects.filter(created_at >= now).values_list('id', flat=True) 

这具有创build对象时存储字段的限制。

其实我的同事提出了以下这个现在看起来很明显的解决办法。 添加一个名为bulk_ref的新列,该列填充一个唯一值并插入每一行。 之后简单地用bulk_ref设置查询表,瞧,你的插入logging被检索。 例如:

 cars = [Car( model="Ford", color="Blue", price="5000", bulk_ref=5, ),Car( model="Honda", color="Silver", price="6000", bulk_ref=5, )] Car.objects.bulk_create(cars) qs = Car.objects.filter(bulk_ref=5) 

可能最简单的解决办法是手动分配主键。 这取决于具体情况,但有时从表开始使用max(id)+1就足够了,并为每个对象分配增加的数字。 但是,如果多个客户端可能同时插入logging,则可能需要一些锁。

django文档目前声明的限制:

如果模型的主键是一个AutoField,它不会像save()那样检索和设置主键属性。

但是,有好消息。 已经有一些关于从内存中bulk_create的门票。 上面列出的票是最有可能有一个解决scheme,即将实施,但显然不能及时或如果它将永远做到这一点。

所以有两种可能的解决scheme,

  1. 等一下,看看这个补丁是否能够生产。 你可以通过testing解决scheme来帮助你,让django社区知道你的想法/问题。 https://code.djangoproject.com/attachment/ticket/19527/bulk_create_and_create_schema_django_v1.5.1.patch

  2. 覆盖/编写您自己的批量插入解决scheme。

这在股票Django中不起作用,但Django bug跟踪器中有一个补丁,它使bulk_create为创build的对象设置主键。

这应该工作。

 categories = Category.objects.bulk_create([ Category(titel="Python", user=user), Category(titel="Django", user=user), Category(titel="HTML5", user=user), ]) >>> categories[0] [<Category: Python>] >>> categories[1] [<Category: Django>]