【问题标题】:How to prefetch_related() for GenericForeignKeys?如何为 GenericForeignKeys 预取相关()?
【发布时间】: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


    【解决方案1】:

    根据我的编辑,当我在序列化程序中查询相关字段而不是将其全部塞入视图的查询集中时,预取会按预期工作。

    【讨论】:

      猜你喜欢
      • 2021-08-15
      • 2020-04-27
      • 1970-01-01
      • 2017-11-05
      • 1970-01-01
      • 2018-12-12
      • 2018-11-11
      • 2020-05-09
      • 2017-10-19
      相关资源
      最近更新 更多