EmbeddedDocumentSerializer为每个ReferenceField运行查询

时间:2016-09-25 19:15:13

标签: mongodb serialization django-rest-framework mongoengine

我有以下模型和序列化程序,目标是在序列化程序运行时只有一个查询:

型号:

class MongoUserSerializer(DocumentSerializer):
    assignees = AssigneeSerializer(many=True)
    class Meta:
        model = MongoUser
        fields = ('id', 'email', 'first_name', 'last_name', 'assignees')
        depth = 2

class AssigneeSerializer(EmbeddedDocumentSerializer):
    class Meta:
        model = Assignee
        fields = ('assignee_first_name', 'assignee_last_name', 'user')
        depth = 0

串行器:

class AssigneeSerializer(EmbeddedDocumentSerializer):
    class Meta:
        model = Assignee
        fields = ('assignee_first_name', 'assignee_last_name', 'user_id')
        depth = 0

当检查mongo分析器时,我有2个查询MongoUser文档。如果我从MongoUserSerializer中删除了assignees字段,那么只有一个查询。

作为一种解决方法,我尝试使用user_id字段仅存储ObjectId并将AssigneeSerializer更改为:

fields = ('assignee_first_name', 'assignee_last_name', 'user_id') 

但是又有2个查询。我认为序列化程序EmbeddedDocumentSerializer获取ReferenceField和

的所有字段和查询
{{1}}

在查询完成后起作用。 如何使用ReferenceField,而不是在序列化时为每个引用运行单独的查询?

2 个答案:

答案 0 :(得分:2)

我最终得到了一种解决方法,而不是使用ReferenceField。相反,我使用的是ObjectIdField:

#user = ReferenceField("MongoUser", required=True) # Removed now
user = ObjectIdField(required=True)

更改了值分配如下:

-        if assignee.user == MongoUser:
+        if assignee.user == MongoUser.id:

这不是最好的方式 - 我们没有使用ReferenceField功能,但它比在序列化器中创建30个查询更好。

最诚挚的问候, 克里斯蒂安

答案 1 :(得分:1)

这是一个非常有趣的问题,我认为它与Mongoengine的DeReference政策有关:https://github.com/MongoEngine/mongoengine/blob/master/mongoengine/dereference.py

即,你的mongoengine文档有一个方法MongoUser.objects.select_related() max_depth参数应该足够大,以至于Mongoengine遍历3个深度级别:MongoUser - > assignees - > Assignee - > user并缓存当前MongoUser实例的所有相关MongoUser个对象。也许,我们应该在DRF-Mongoengine的DocumentSerializers中的某个地方调用这个方法来预取关系,但目前我们还没有。

请参阅this post关于经典DRF + Django ORM解释,如何通过在经典DRF中进行预取来解决N + 1请求问题。基本上,您需要覆盖get_queryset()的{​​{1}}方法才能使用ModelViewSet方法:

select_related()

不幸的是,我不认为DRF-Mongoengine中的from rest_framework_mongoengine.viewsets import ModelViewSet class MongoUserViewSet(ModelViewSet): def get_queryset(self): queryset = MongoUser.objects.all() # Set up eager loading to avoid N+1 selects queryset.select_related(max_depth=3) return queryset current implementation足够聪明,可以恰当地处理这些查询集。可能ReferenceField会有效吗?

尽管如此,我还没有使用过这个功能,也没有足够的时间自己玩这些设置,所以如果你分享了你的发现,我会感激你。