You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django电商模型高效联查:避免重复过滤与数据冗余

这个场景我太熟了!既要一次过滤产品,又要避免大字段重复传输,还要减少数据库查询次数,刚好有个完美的解决方案,结合Django的prefetch_related和DRF的嵌套序列化器就能搞定,而且代码很简洁:

首先先修正下你模型里的拼写小问题(不然后续容易踩坑):

class Product(models.Model):
    name = models.CharField(max_length=300)
    description = models.CharField(max_length=10000)

class Thumbnail(models.Model):
    thumbnail = models.ImageField(null=True)
    # 把related_name改成更直观的thumbnails,方便后续调用
    product = models.ForeignKey(Product, related_name='thumbnails', on_delete=models.CASCADE)

核心思路:一次过滤+预取关联+嵌套序列化

  1. 只做一次关键词过滤:在产品查询集里完成关键词匹配,不用再对缩略图重复过滤
  2. 用prefetch_related减少查询次数:批量获取所有匹配产品的缩略图,避免N+1数据库查询(原来的两次视图集查询会导致多次DB请求,这个方法只需要2次查询:一次产品,一次批量缩略图)
  3. 嵌套序列化器避免冗余:让产品的description只在产品层级返回一次,缩略图作为产品的一个数组字段返回

接下来是序列化器代码:

from rest_framework import serializers

class ThumbnailSerializer(serializers.ModelSerializer):
    class Meta:
        model = Thumbnail
        fields = ['thumbnail']  # 只返回需要的缩略图字段

class ProductSerializer(serializers.ModelSerializer):
    # 嵌套缩略图序列化器,many=True表示是多个缩略图
    thumbnails = ThumbnailSerializer(many=True, read_only=True)

    class Meta:
        model = Product
        fields = ['name', 'description', 'thumbnails']

然后是视图集,这里用ReadOnlyModelViewSet就行(如果需要增删改就用ModelViewSet):

from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer

class ProductViewSet(viewsets.ReadOnlyModelViewSet):
    serializer_class = ProductSerializer

    def get_queryset(self):
        # 基础查询集
        queryset = Product.objects.all()
        # 获取用户输入的关键词
        keyword = self.request.query_params.get('keyword', None)
        if keyword:
            # 只做一次关键词过滤,匹配产品名称
            queryset = queryset.filter(name__icontains=keyword)
        # 预取所有关联的缩略图,避免多次查询
        queryset = queryset.prefetch_related('thumbnails')
        return queryset

这样返回的响应结构会是这样的,完美符合你的需求:

[
    {
        "name": "无线蓝牙耳机",
        "description": "这是一段很长很长的产品描述,只会在这里出现一次...",
        "thumbnails": [
            {"thumbnail": "/media/thumb1.jpg"},
            {"thumbnail": "/media/thumb2.jpg"}
        ]
    },
    {
        "name": "智能手表",
        "description": "另一段长描述,也只出现一次...",
        "thumbnails": [
            {"thumbnail": "/media/watch_thumb.jpg"}
        ]
    }
]

补充说明

你之前提到的select_related其实更适合正向关联(比如从Thumbnail查对应的Product),而我们这里是从Product查它的所有Thumbnail,属于反向多对一关联,所以用prefetch_related才是正确的选择,它会一次性批量获取所有匹配产品的缩略图,大幅提升性能。

如果你的缩略图数量特别多,还可以考虑给Thumbnail加分页,但一般电商场景下这个方案完全够用啦!

内容的提问来源于stack exchange,提问作者dejandenib

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:25:11