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)
核心思路:一次过滤+预取关联+嵌套序列化
- 只做一次关键词过滤:在产品查询集里完成关键词匹配,不用再对缩略图重复过滤
- 用prefetch_related减少查询次数:批量获取所有匹配产品的缩略图,避免N+1数据库查询(原来的两次视图集查询会导致多次DB请求,这个方法只需要2次查询:一次产品,一次批量缩略图)
- 嵌套序列化器避免冗余:让产品的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
相关产品推荐
相关产品推荐

