How to get primary keys of objects created using django bulk_create

依然范特西╮ 提交于 2019-12-18 11:40:07

问题


Is there a way to get the primary keys of the items you have created using the bulk_create feature in django 1.4+?


回答1:


2016

Since Django 1.10 - it's now supported (on Postgres only) here is a link to the 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

From the change log:

Changed in Django 1.10: Support for setting primary keys on objects created using bulk_create() when using PostgreSQL was added




回答2:


According to the documentation you can't do it: https://docs.djangoproject.com/en/dev/ref/models/querysets/#bulk-create

bulk-create is just for that: create a lot of objects in an efficient way saving a lot of queries. But that means that the response you get is kind of incomplete. If you do:

>>> 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]

That doesn't mean your categories doesn't have pk, just that the query didn't retrieve them (if the key is an AutoField). If you want the pks for some reason you will need to save the objects in a classic way.




回答3:


Two approaches I can think of:

a) You could do

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)

This could be a little expensive if the queryset is extremely huge.

b) If the model has a created_at field,

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)

This has the limitation of having a field that stores when the object was created.




回答4:


Actually my colleague has suggested the following solution which seems all so obvious now. Add a new column called bulk_ref which you populate with a unique value and insert for every row. Afterwards simply query the table with the bulk_ref set beforehand and voila, your inserted records are retrieved. e.g.:

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)



回答5:


The django documentation currently states under the limitations:

If the model’s primary key is an AutoField it does not retrieve and set the primary key attribute, as save() does.

But, there is good news. There has been a couple of tickets talking about bulk_create from memory. The ticket listed above is the most likely to have a solution which will soon be implemented but obviously there is no guarantee on time or if it will ever make it.

So there are two possible solutions,

  1. Wait and see if this patch makes it to production. You can help with this by testing out the stated solution and let the django community know your thoughts / issues. https://code.djangoproject.com/attachment/ticket/19527/bulk_create_and_create_schema_django_v1.5.1.patch

  2. Override / write your own bulk insert solution.




回答6:


Probably the simplest workaround is manually assigning primary keys. It depends on particular case, but sometimes it's enough to start with max(id)+1 from table and assign numbers incrementing on every object. However if several clients may insert records simultaneously some lock may be needed.




回答7:


This doesn't work in stock Django, but there is a patch in the Django bug tracker that makes bulk_create set the primary keys for created objects.




回答8:


This should work.

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>]


来源:https://stackoverflow.com/questions/15933689/how-to-get-primary-keys-of-objects-created-using-django-bulk-create

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!