Django的bulk_create()可以外键吗?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django的bulk_create()可以外键吗?相关的知识,希望对你有一定的参考价值。
我需要一次创建很多EVENT对象,然后创建很多ARCHIVED_EVENT对象,这些对象的外键是对应事件的。
我的代码看起来是这样的。
events = []
archivedEvents = []
for _ in range(1000):
event = Event(name="Test")
archivedEvent = ArchivedEvent(event_id=event.id)
archivedEvents.append(archivedEvent)
events.append(event)
Event.objects.bulk_create(events)
ArchivedEvent.objects.bulk_create(archivedEvents)
不幸的是,所有在这里创建的ARCHIVED_EVENT对象的外键都是NULL。我知道一个对象的主键在保存到数据库之前不会生成。但我在创建归档事件之前保存了事件。我是不是遗漏了什么? 在批量创建归档事件之前,我是否应该刷新缓存?
答案
event.id不会被创建,除非通过 bulk_create()
. 也许你可以使用另一个循环来创建 ArchivedEvent
. 像这样。
events = []
archivedEvents = []
for _ in range(1000):
event = Event(name="Test")
events.append(event)
events = Event.objects.bulk_create(events)
for event in events:
archivedEvent = ArchivedEvent(event_id=event.id)
archivedEvents.append(archivedEvent)
ArchivedEvent.objects.bulk_create(archivedEvents)
根据文档,这个解决方案适用于Postgresql。如果你有其他的数据库,那就像这样尝试。
events = []
archivedEvents = []
for _ in range(1000):
event = Event(name="Test")
events.append(event)
Event.objects.bulk_create(events)
events = Event.objects.all().order_by('-id')[:1000][::-1]
for event in events:
archivedEvent = ArchivedEvent(event_id=event.id)
archivedEvents.append(archivedEvent)
ArchivedEvent.objects.bulk_create(archivedEvents)
为了避免竞赛条件,你可以预先生成主键,然后使用它们。比如说
last_event_id = Event.objects.last().id + 1000 # getting last event id and adding thousand to avoid duplicates.
events = [x+last_event_id for x in range(1000)]
archivedEvents = []
for e in events:
event = Event(name="Test",pk=e)
events.append(event)
archivedEvent = ArchivedEvent(event_id=e)
archivedEvents.append(archivedEvent)
Event.objects.bulk_create(events)
ArchivedEvent.objects.bulk_create(archivedEvents)
另一答案
下面是一个基于@ruddra的其他数据库解决方案的 避免使用数据库锁的竞赛条件的解决方案。希望能帮到你。
from django.db import transaction
with transaction.atomic():
# lock first row to avoid race condition
# note: first row of Event table must have content,
# if not, you need use other tables's not empty row to add lock.
Event.objects.select_for_update().first()
# just @ruddra's mysql solution
events = []
archivedEvents = []
for _ in range(1000):
event = Event(name="Test")
events.append(event)
Event.objects.bulk_create(events)
event_ids = Event.objects.values_list('id', flat=True).order_by('-id')[:1000][::-1]
for event_id in event_ids:
archivedEvent = ArchivedEvent(event_id=event_id)
archivedEvents.append(archivedEvent)
ArchivedEvent.objects.bulk_create(archivedEvents)
以上是关于Django的bulk_create()可以外键吗?的主要内容,如果未能解决你的问题,请参考以下文章