我的模型有外键关系的情况:
# models.py
class Child(models.Model):
parent = models.ForeignKey(Parent,)
class Parent(models.Model):
pass
和我的序列化器:
class ParentSerializer(serializer.ModelSerializer):
child = serializers.SerializerMethodField('get_children_ordered')
def get_children_ordered(self, parent):
queryset = Child.objects.filter(parent=parent).select_related('parent')
serialized_data = ChildSerializer(queryset, many=True, read_only=True, context=self.context)
return serialized_data.data
class Meta:
model = Parent
当我在视图中调用 Parent 以获得 N 个父级时,Django 在获取子级时会在序列化器内执行 N 次数据库调用。有什么方法可以让所有父母的所有孩子都最小化数据库调用次数吗?
我已经尝试过,但它似乎没有解决我的问题:
class ParentList(generics.ListAPIView):
def get_queryset(self):
queryset = Parent.objects.prefetch_related('child')
return queryset
serializer_class = ParentSerializer
permission_classes = (permissions.IsAuthenticated,)
EDIT
我更新了下面的代码以反映 Alex 的反馈......这解决了一个嵌套关系的 N+1 问题。
# serializer.py
class ParentSerializer(serializer.ModelSerializer):
child = serializers.SerializerMethodField('get_children_ordered')
def get_children_ordered(self, parent):
# The all() call should hit the cache
serialized_data = ChildSerializer(parent.child.all(), many=True, read_only=True, context=self.context)
return serialized_data.data
class Meta:
model = Parent
# views.py
class ParentList(generics.ListAPIView):
def get_queryset(self):
children = Prefetch('child', queryset=Child.objects.select_related('parent'))
queryset = Parent.objects.prefetch_related(children)
return queryset
serializer_class = ParentSerializer
permission_classes = (permissions.IsAuthenticated,)
现在假设我还有一个模型,它是孙子模型:
# models.py
class GrandChild(models.Model):
parent = models.ForeignKey(Child,)
class Child(models.Model):
parent = models.ForeignKey(Parent,)
class Parent(models.Model):
pass
如果我将以下内容放入我的views.py
为家长queryset
:
queryset = Parent.objects.prefetch_related(children, 'children__grandchildren')
看起来这些孙子并没有被带入 ChildSerializer,因此,我再次运行另一个 N+1 问题。对这个有什么想法吗?
EDIT 2
也许这会提供清晰的信息...也许我仍然遇到 N + 1 数据库调用的原因是因为我的子类和孙子类都是多态的...即
# models.py
class GrandChild(PolymorphicModel):
child = models.ForeignKey(Child,)
class GrandSon(GrandChild):
pass
class GrandDaughter(GrandChild):
pass
class Child(PolymorphicModel):
parent = models.ForeignKey(Parent,)
class Son(Child):
pass
class Daughter(Child):
pass
class Parent(models.Model):
pass
我的序列化器看起来更像这样:
# serializer.py
class ChildSerializer(serializer.ModelSerializer):
grandchild = serializers.SerializerMethodField('get_children_ordered')
def to_representation(self, value):
if isinstance(value, Son):
return SonSerializer(value, context=self.context).to_representation(value)
if isinstance(value, Daughter):
return DaughterSerializer(value, context=self.context).to_representation(value)
class Meta:
model = Child
class ParentSerializer(serializer.ModelSerializer):
child = serializers.SerializerMethodField('get_children_ordered')
def get_children_ordered(self, parent):
queryset = Child.objects.filter(parent=parent).select_related('parent')
serialized_data = ChildSerializer(queryset, many=True, read_only=True, context=self.context)
return serialized_data.data
class Meta:
model = Parent
另外,对于孙女、孙子来说也是如此,我不会为您提供代码细节,但我想您已经明白了。
当我运行 ParentList 视图并监视数据库查询时,我得到了大约 1000 个查询的信息,仅针对少数家长。
如果我在 django shell 中运行相同的代码,我可以在不超过 25 个查询的情况下完成相同的查询。我怀疑这可能与我使用 django 多态库有关?原因是,数据库中还有一个Child和GrandChild表,再加上每个Son/Daughter、孙/孙女表,总共6个表。跨越那些物体。所以我的直觉告诉我我错过了那些多态表。
或者也许我的数据模型有更优雅的解决方案?