Django在创建过程中将对象添加到Related Manager

时间:2018-05-16 18:51:42

标签: django django-rest-framework

考虑一个简单的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。

2 个答案:

答案 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)

在对QuerySetModel源代码进行一些调查后,我决定最好/唯一的选择是直接修改每个对象上的_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,这对我来说不是问题。