Как использовать функцию prefetch_related() для GenericForeignKeys?
У меня есть List, состоящий из ListItems. Эти ListItems затем указывают на модель ParentItem или ChildItem через GenericForeignKey:
# 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):
parent_title = models.CharField()
class ChildItem(models.Model):
child_title = models.CharField()
parent = models.ForeignKey(ParentItem, related_name="child")
Я хочу отобразить список всех моих списков с их ListItems и соответствующими данными ItemA/ItemB, используя ListSerializer:
# serializers.py
class ParentItemSerializer(serializers.ModelSerializer):
class Meta:
model = ParentItem
fields = ["parent_title"]
class ChildItemSerializer(serializers.ModelSerializer):
parent = ParentItemSerializer()
class Meta:
model = ChildItem
fields = ["child_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_title",
"list_items__content_object__child_title",
"list_items__content_object__parent",
"list_items__content_object__parent__parent_title",
)
Я прочитал документацию по prefetch_related, которая предполагает, что это должно работать:
Хотя prefetch_related поддерживает предварительную выборку GenericForeignKey отношения, количество запросов будет зависеть от данных. Поскольку GenericForeignKey может ссылаться на данные в нескольких таблицах, требуется один запрос на каждую таблицы, а не один запрос для всех элементов. Могут быть дополнительные запросы к таблице ContentType, если соответствующие строки еще не были извлечены.
но я не знаю, применимо ли это к DRF.
Согласно моей правке, предварительная выборка работает как положено, когда я перемещаю соответствующие поля, когда они запрашиваются в сериализаторе, вместо того, чтобы запихивать все это в кверисет представления.