考虑一个简单的ForeignKey关系:
class A(Model):
pass
class B(Model):
a = ForeignKey(A)
我有一个API视图,它根据外部数据(未从用户传递的数据)创建A和一组B,然后序列化创建的对象并返回序列化数据。我的对象创建代码类似于:
a = A()
a.b_set.bulk_create(B(a=a) for b in [...])
我的问题是,这不会将B对象添加到b_set中,所以如果我要运行
print(a.b_set.all())
之后,它将重新查询数据库以获取b_set。这是不必要的,因为我刚刚创建了它的整个b_set。我正在使用一系列嵌套对象执行此操作,因此会导致大量不必要的查询。我目前的解决方法是在创建后运行像
这样的查询A.objects.prefetch_related('b_set').get(a=a.id)
然后获取对象的序列化程序。这将序列化限制为只有一个不必要的查询,但我也想消除那个问题。在我看来应该有一种方法来缓存创建的B对象,并消除 任何需要在序列化期间再次命中DB。
答案 0 :(得分:0)
我认为您需要先执行a.save()
才能bulk_create
。以下是使用您描述的两个模型的结果:
a = A()
a.save()
a.b_set.bulk_create([B(a=a), B(a=a), B(a=a)])
a.b_set.count()
>>> 3
答案 1 :(得分:0)
在对QuerySet
和Model
源代码进行一些调查后,我决定最好/唯一的选择是直接修改每个对象上的_prefetched_objects_cache
。绝对不漂亮,但它的工作原理。以下是我所做的要点:
a = A()
b_set = a.b_set.bulk_create(B(a=a) for b in [...])
a._prefetch_related_cache = {}
a._prefetch_related_cache['b_set'] = b_set
这可以确保所有创建的B都缓存在a
上。请注意,如果B
具有自动创建的主键字段,则bulk_create
返回的对象中的大多数后端都不会填充这些字段。幸运的是我正在使用从bulk_create
返回自动PK的PostgreSQL,这对我来说不是问题。