UFO ET IT

django bulk_create를 사용하여 생성 된 객체의 기본 키를 얻는 방법

ufoet 2020. 11. 27. 21:49
반응형

django bulk_create를 사용하여 생성 된 객체의 기본 키를 얻는 방법


django 1.4 이상에서 bulk_create 기능을 사용하여 만든 항목의 기본 키를 얻는 방법이 있습니까?


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

변경 로그에서 :

Django 1.10에서 변경 : PostgreSQL을 사용할 때 bulk_create ()를 사용하여 생성 된 객체에 대한 기본 키 설정 지원이 추가되었습니다.


문서에 따르면 할 수 없습니다 : https://docs.djangoproject.com/en/dev/ref/models/querysets/#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]

그렇다고 카테고리에 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)

이것은 객체가 생성 될 때 저장되는 필드를 갖는 한계가 있습니다.


실제로 제 동료는 지금 매우 분명해 보이는 다음 솔루션을 제안했습니다. 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)

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.


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.


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.


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

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

반응형