【发布时间】:2021-11-09 06:31:31
【问题描述】:
我有一个由 ListItems 组成的列表。这些 ListItem 然后通过 GenericForeignKey 指向 ParentItem 或 ChildItem 模型:
# models.py
class List(models.Model):
title = models.CharField()
class ListItem(models.Model):
list = models.ForeignKey(List, related_name="list_items")
order = models.PositiveSmallIntegerField()
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey("content_type", "object_id")
class ParentItem(models.Model):
title = models.CharField()
class ChildItem(models.Model):
title = models.CharField()
parent = models.ForeignKey(ParentItem, related_name="child")
我想使用 ListSerializer 显示我的所有列表及其 ListItems 和相应的 ItemA/ItemB 数据:
# serializers.py
class ParentItemSerializer(serializers.ModelSerializer):
class Meta:
model = ParentItem
fields = ["title"]
class ChildItemSerializer(serializers.ModelSerializer):
parent = ParentItemSerializer()
class Meta:
model = ChildItem
fields = ["title", "parent"]
class ListItemSerializer(serializers.ModelSerializer):
contents = serializers.SerializerMethodField()
class Meta:
model = ListItem
fields = ["contents"]
def get_contents(self, obj):
item = obj.content_object
type = item.__class__.__name__
if type == "ParentItem":
return ParentItemSerializer(item).data
elif type == "ChildItem":
return ChildItemSerializer(item).data
class ListSerializer(serializers.ModelSerializer):
items = serializers.SerializerMethodField()
class Meta:
model = List
fields = ["title", "items"]
def get_items(self, obj):
return ListItemSerializer(obj.list_items, many=True).data
如何优化我的 List 查询集以预取这些 GenericForeignKey 关系?
# views.py
class ListViewSet(viewset.ModelViewSet):
queryset = List.objects.all()
serializer_class = ListSerializer
List.objects.all().prefetch_related("list_items") 有效,但以下似乎无效:
List.objects.all().prefetch_related(
"list_items",
"list_items__content_object",
"list_items__content_object__parent",
)
我已阅读 the documentation on prefetch_related,这表明它应该可以工作:
虽然 prefetch_related 支持预取 GenericForeignKey 关系,查询的数量将取决于数据。由于一个 GenericForeignKey 可以引用多个表中的数据,每个表一个查询 需要引用的表,而不是对所有项目进行一次查询。 如果 ContentType 表上可能有其他查询 尚未提取相关行。
但我不知道这是否适用于 DRF。
编辑:当我将一些预取移到序列化程序时,会取得更好的成功:
class ListSerializer(serializers.ModelSerializer):
def get_items(self, obj):
return ListItemSerializer(obj.list_items.all().prefetch_related("content_object"), many=True).data
【问题讨论】:
标签: django django-rest-framework