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

Django查询:获取每个产品对应各卖家的最新价格

解决Django比价应用中「每个产品对应各卖家最新价格」的问题

嘿,这个需求我之前做电商比价系统的时候刚好碰到过!咱们核心要解决的就是去重(每个卖家仅显示一次)+ 取最新价格的问题,直接遍历所有价格记录肯定会重复,得用Django ORM的子查询和预取来高效实现。

思路分析

我们需要先筛选出「每个产品+每个卖家」组合下的最新一条价格记录,然后把这些记录和产品关联起来,避免模板里出现重复的卖家。

具体实现步骤

1. 优化查询集(核心代码)

用Subquery和Prefetch来高效获取每个产品对应的最新价格集合,避免N+1查询:

from django.db.models import Max, OuterRef, Subquery, Prefetch

# 第一步:子查询 - 找出每个产品下,每个卖家的最新价格的添加时间
latest_added_per_seller = Price.objects.filter(
    part=OuterRef('pk')  # 关联外部的Part对象
).values('seller').annotate(
    latest_added=Max('added')  # 每个卖家对应这个产品的最新时间
).values('latest_added')  # 只取时间值,用于后续过滤

# 第二步:预取每个产品对应的所有最新价格记录(每个卖家仅一条)
parts = Part.objects.prefetch_related(
    Prefetch(
        'partprice',  # 关联Part模型的related_name
        queryset=Price.objects.filter(
            added__in=Subquery(latest_added_per_seller)  # 筛选出最新时间的价格
        ).order_by('-added'),  # 按时间从新到旧排序
        to_attr='latest_prices'  # 把结果存到自定义属性里,方便模板调用
    )
).all()

2. 修改模板代码

现在模板里可以直接遍历预取好的latest_prices,每个卖家只会出现一次:

{% for part in parts %}
    <h3>{{ part.name }}</h3>
    {% for price in part.latest_prices %}
        <a href="{{ part.seller1URL }}">
            <p>${{ price.price }} - {{ price.seller.name }}</p>
        </a>
    {% empty %}
        <p>该产品暂无任何价格记录</p>
    {% endfor %}
{% endfor %}

3. 进阶:显示所有卖家(无价格则留空)

如果你的需求是不管产品有没有某卖家的价格,都要显示该卖家(无价格时留空),可以按以下方式处理:

第一步:获取所有卖家列表

# 在视图里先拿到所有卖家
sellers = Seller.objects.all()
# 把sellers传到模板上下文
context = {'parts': parts, 'sellers': sellers}

第二步:自定义模板过滤器

在你的app下创建templatetags/custom_filters.py(如果没有templatetags文件夹就新建一个,记得加__init__.py):

from django import template

register = template.Library()

@register.filter
def get_latest_price(price_list, seller):
    """根据卖家从价格列表中找到对应的最新价格"""
    for price in price_list:
        if price.seller == seller:
            return price
    return None

第三步:修改模板

{% load custom_filters %}  <!-- 先加载自定义过滤器 -->

{% for part in parts %}
    <h3>{{ part.name }}</h3>
    {% for seller in sellers %}
        {% with price=part.latest_prices|get_latest_price:seller %}
            {% if price %}
                <a href="{{ part.seller1URL }}">
                    <p>${{ price.price }} - {{ seller.name }}</p>
                </a>
            {% else %}
                <p>{{ seller.name }}: 暂无价格</p>
            {% endif %}
        {% endwith %}
    {% endfor %}
{% endfor %}

为什么这么做?

  • 用Subquery和Prefetch把查询次数降到最低,避免了模板里遍历所有价格记录的性能问题
  • 确保每个卖家仅显示一次,且是最新的价格
  • 进阶方案可以覆盖「显示所有卖家」的需求,无价格时友好提示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 17:06:51