首页 > 解决方案 > Django REST framework 一对多关系和数据库查询

问题描述

我是 django 的新手,我正在使用 Django REST 框架开发我的第一个项目。

楷模:

class Sticker(Model):
    image = models.ImageField(upload_to=sticker_image_directory_path, null=False)
    title = models.CharField(max_length=150)

    def __str__(self):
        return self.title

class StickerTag(Model):
    name = models.CharField(max_length=100)
    sticker = models.ForeignKey(Sticker, on_delete=models.RESTRICT, related_name='tags')

    def __str__(self):
        return self.name

序列化器:

class StickerSerializer(serializers.ModelSerializer):
    tags = serializers.StringRelatedField(many=True)
    
    class Meta:
        model = models.Sticker
        fields = ['id', 'image', 'title', 'tags', 'countries']

看法:

class StickerView(mixins.ListModelMixin,
                  viewsets.GenericViewSet):
    serializer_class = serializers.StickerSerializer
    queryset = models.Sticker.objects.all()

我正在调试对http://127.0.0.1:8000/stickers/with 的调用django-debug-toolbar。我很惊讶地看到,对于每个贴纸实例,Django 都会像这样对贴纸标签表进行查询:

SELECT `stickerapp_stickertag`.`id`,
       `stickerapp_stickertag`.`name`,
       `stickerapp_stickertag`.`sticker_id`
  FROM `stickerapp_stickertag`
 WHERE `stickerapp_stickertag`.`sticker_id` = 1

意味着它正在为每个贴纸一张一张地抓取贴纸标签。因此,如果有 10 个贴纸,它将使用上述查询进行 10 次 DB 调用。但我认为这些查询太多了,可以通过使用 MYSQL 的“IN”子句来减少,例如:

SELECT * FROM stickerapp_stickertag where sticker_id in (1,2,3,4,5);

我不知道如何在 Django REST 框架中做到这一点。请指导!

标签: pythonmysqldjangodjango-rest-framework

解决方案


您可以.prefetch_related(…)[Django-doc]相关Tag对象:

class StickerView(mixins.ListModelMixin, viewsets.GenericViewSet):
    serializer_class = serializers.StickerSerializer
    queryset = models.Sticker.objects.prefetch_related('tags')

这将进行两个查询,第一个查询获取所有Sticker对象,然后第二个查询将为每个查询Sticker获取相关标签。这是在对所有 Stickers的单个查询中完成的。


推荐阅读