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

Django序列化器:实现单店最新价格展示及商品最低价排序

解决方案

针对你的两个需求,我们可以通过子查询筛选最新价格和数据库注释实现按最低价排序来解决,无需修改数据库关联关系,具体步骤如下:


1. 修改序列化器,补充商店信息(贴合需求)

先在PriceSerializer中添加商店名称字段,让返回的价格数据明确对应所属商店:

# serializers.py
from .models import Article, Price, Shop
from rest_framework import serializers

class PriceSerializer(serializers.ModelSerializer):
    shop_name = serializers.CharField(source='shop.name')  # 新增商店名称字段
    class Meta:
        model = Price
        fields = ['shop_name', 'name', 'date']  # 调整字段顺序,显示更清晰

class ArticleSerializer(serializers.ModelSerializer):
    prices = PriceSerializer(many=True)
    class Meta:
        model = Article
        fields = ['name', 'prices']

2. 调整视图集,筛选最新价格并实现排序

在ArticleViewSet中,通过子查询获取每个商品-商店组合的最新价格,同时计算商品的最低价格用于排序:

# views.py
from .models import Shop, Article, Price
from rest_framework import viewsets, permissions, filters
from apitest.serializers import ArticleSerializer, PriceSerializer, ShopSerializer
from django.db.models import Prefetch, Subquery, OuterRef, Max, Min, Func, F, Value, Q
from django.db.models.fields import FloatField

class ArticleViewSet(viewsets.ModelViewSet):
    serializer_class = ArticleSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['^name']

    def get_queryset(self):
        # 子查询:获取每个(商品, 商店)组合的最新价格日期
        latest_date_subquery = Price.objects.filter(
            article=OuterRef('article'),
            shop=OuterRef('shop')
        ).values('article', 'shop').annotate(max_date=Max('date')).values('max_date')

        # 筛选出所有符合最新日期的价格记录
        latest_prices = Price.objects.filter(date=Subquery(latest_date_subquery))

        # 预加载每个商品的最新价格,避免N+1查询
        queryset = Article.objects.prefetch_related(
            Prefetch('prices', queryset=latest_prices)
        )

        # 注释每个商品的最低价格:将字符串格式的价格(如"12,99")转为浮点数后取最小值
        queryset = queryset.annotate(
            min_price=Min(
                Func(
                    F('prices__name'),
                    Value(','),
                    Value('.'),
                    function='replace',
                    output_field=FloatField()
                ),
                filter=Q(prices__isnull=False)
            )
        )

        # 按最低价格升序排序,无价格的商品默认排在最后
        return queryset.order_by('min_price', 'name')

# 其余视图集代码保持不变
class PriceViewSet(viewsets.ModelViewSet):
    queryset = Price.objects.all()
    serializer_class = PriceSerializer
    permission_classes = [permissions.IsAuthenticated]

class ShopViewSet(viewsets.ModelViewSet):
    queryset = Shop.objects.all()
    serializer_class = ShopSerializer
    permission_classes = [permissions.IsAuthenticated]

代码说明

  1. 子查询筛选最新价格:

    • 通过latest_date_subquery获取每个商品-商店组合的最大日期(即最新价格的日期)
    • 再用该日期过滤Price表,得到每个商品对应每个商店的唯一最新价格记录
    • 用Prefetch预加载这些记录,避免序列化时触发重复数据库查询
  2. 按最低价排序:

    • 调用数据库replace函数,把价格字符串中的逗号替换为点,转成可计算的浮点数
    • 用Min函数计算每个商品所有最新价格中的最小值,作为排序依据
    • 查询集按min_price升序排序,无价格的商品因min_price为null自动排在末尾

最终效果

修改后返回的JSON格式如下:

[
    {
        "name": "Flashlight",
        "prices": [
            {
                "shop_name": "Shop A",
                "name": "12,99",
                "date": "2022-12-22"
            },
            {
                "shop_name": "Shop B",
                "name": "14,99",
                "date": "2022-12-22"
            }
        ]
    },
    {
        "name": "Cup",
        "prices": []
    }
]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 23:25:17