如何获取使用django bulk_create创建的对象的主键

mik*_*kec 65 django django-models django-queryset django-views

有没有办法使用django 1.4+中的bulk_create功能获取您创建的项目的主键?

Or *_*uan 55

2016

从Django 1.10开始 - 它现在支持(仅在Postgres上),这里是doc链接.

>>> list_of_objects = Entry.objects.bulk_create([
...     Entry(headline="Django 2.0 Released"),
...     Entry(headline="Django 2.1 Announced"),
...     Entry(headline="Breaking: Django is awesome")
... ])
>>> list_of_objects[0].id
1
Run Code Online (Sandbox Code Playgroud)

从更改日志中:

更改了Django 1.10:添加了在使用PostgreSQL时使用bulk_create()创建的对象上设置主键的支持

  • 欢迎来到未来 (7认同)
  • 刚刚在文档中找到了这一点:在支持它的数据库(除 Oracle 之外的所有数据库)上,将ignore_conflicts 参数设置为 True 告诉数据库忽略插入失败约束(例如重复的唯一值)的任何行的失败。启用此参数将禁用在每个模型实例上设置主键(如果数据库通常支持它)。 (5认同)
  • 如果在mysql中怎么办?bulk_create创建的条目在数据库中是否有id值? (4认同)
  • 还有人在 PostgreSQL 上没有返回任何内容吗? (4认同)
  • 伤心我是一个 mysql 用户 (2认同)
  • @MohammedShareefC 它将获取数据库中的一个主键,但是`bulk_create` 方法返回的列表与您提供的列表相同,并且本地对象(该列表的成员)没有将其设置为 [pyriku 在他的答案](/sf/answers/1188721341/)。 (2认同)
  • 在支持它的数据库(除 PostgreSQL < 9.5 和 Oracle 之外的所有数据库)上,将ignore_conflicts 参数设置为 True 告诉数据库忽略插入任何未通过约束(例如重复的唯一值)的行的失败。启用此参数将禁用在每个模型实例上设置主键(如果数据库通常支持它)。 (2认同)

pyr*_*iku 28

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

bulk-create就是为了这个:以有效的方式创建大量对象,从而节省了大量的查询.但这意味着你得到的反应有点不完整.如果你这样做:

>>> 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]
Run Code Online (Sandbox Code Playgroud)

这并不意味着您的类别没有pk,只是查询没有检索它们(如果键是一个AutoField).如果由于某种原因需要pks,则需要以经典方式保存对象.

  • 我认为这是问题的关键,或者至少我是如何解释它的,即:人们使用什么技术来解决`bulk_create`的限制,以便可靠地检索创建的ID? (17认同)
  • 有一个开放的PR在这里添加对从bulk_create返回ID的支持:https://github.com/django/django/pull/5166值得注意的是Postgres支持返回ID,因此有一种方法可以通过原始sql操作立即获取ID . (3认同)

kar*_*ikr 24

我能想到的两种方法:

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)
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

这具有存储在创建对象时存储的字段的限制.

  • 你知道,我已经有一个`date_created`字段,所以这可以工作,尽管最后添加一个是最小的努力.我唯一担心的是多个查询可能同时命中数据库,所以我想我需要在`bulk_create`之前和`created_at`查询之后实现某种锁定机制. (2认同)

Dan*_*anH 11

实际上我的同事提出了以下解决方案,现在看来这一切都很明显.添加一个新列bulk_ref,使用唯一值填充该列,并为每一行插入.然后,只需bulk_ref事先用设置查询表,然后检索插入的记录.例如:

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)
Run Code Online (Sandbox Code Playgroud)

  • 向模型添加其他字段以解决查询问题并不是一个好习惯. (12认同)
  • 虽然这是事实,但无论如何,批量插入都应该被视为一种优化,这必然会损害设计。这里需要平衡“不够快”和“设计不完美”之间的紧张关系。在 Django PR 5166 投入使用之前,对于需要优化批量插入的团队来说,这可能是一个合理的妥协。 (2认同)