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

如何使用Django ORM对查询集进行价格分箱统计?

使用Django ORM按价格区间统计产品数据

嘿,针对你提出的按价格区间统计产品总数、总销售额、平均销售额的需求,我结合你给出的Django模型,整理了两种可行的实现方案,对应你提到的两个思路:

先看你的模型结构

from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=264)
    
    def __str__(self):
        return self.name
    
    class Meta:
        verbose_name_plural = "categories"

class Status(models.Model):
    name = models.CharField(max_length=264)
    
    def __str__(self):
        return self.name
    
    class Meta:
        verbose_name_plural = "status"

class Product(models.Model):
    title = models.CharField(max_length=264)
    description = models.CharField(max_length=264)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    price = models.DecimalField(max_digits=10, decimal_places=2)  # 补充decimal_places,原模型遗漏该参数
    status = models.ForeignKey(Status, on_delete=models.CASCADE)

方案一:查询集转列表后用Python函数处理

这种方法适合数据量不大的场景,逻辑直观,容易调整区间规则:

  1. 先获取目标产品数据集(可按需添加过滤条件,比如特定分类、在售状态)
  2. 定义价格区间规则,遍历产品列表完成归类统计

示例代码:

from .models import Product

def stats_by_price_range():
    # 定义价格区间:键为区间名称,值为(下限, 上限),明确边界逻辑
    price_ranges = {
        "0-100": (0, 100),
        "100-500": (100, 500),
        "500-1000": (500, 1000),
        "1000+": (1000, float('inf'))
    }
    
    # 获取产品数据,可添加filter筛选目标产品
    products = Product.objects.all()
    
    # 初始化统计结果容器
    stats = {range_name: {"total_count": 0, "total_sales": 0, "avg_price": 0} for range_name in price_ranges}
    
    for product in products:
        for range_name, (low, high) in price_ranges.items():
            if low <= product.price < high:
                stats[range_name]["total_count"] += 1
                stats[range_name]["total_sales"] += product.price
                break  # 找到对应区间后跳出循环,避免重复判断
    
    # 计算各区间平均价格
    for range_name in stats:
        count = stats[range_name]["total_count"]
        if count > 0:
            stats[range_name]["avg_price"] = stats[range_name]["total_sales"] / count
    
    return stats

调用该函数即可得到每个区间的完整统计数据。


方案二:直接用Django ORM在数据库层面分箱统计

这种方法效率更高,适合大数据量场景,所有统计逻辑由数据库完成,无需将全量数据加载到Python内存:

核心思路是用Case和When给每个产品标记所属价格区间,再按区间分组完成统计计算。

示例代码:

from django.db.models import Case, When, Value, Count, Sum, Avg
from .models import Product

def stats_by_price_range_orm():
    # 定义价格区间判断规则,明确边界避免重复统计(示例中0-100包含100,100-500包含500)
    price_range_case = Case(
        When(price__lte=100, then=Value("0-100")),
        When(price__gt=100, price__lte=500, then=Value("100-500")),
        When(price__gt=500, price__lte=1000, then=Value("500-1000")),
        When(price__gt=1000, then=Value("1000+")),
        output_field=models.CharField(),
    )
    
    # 执行分组统计
    stats_queryset = Product.objects.annotate(
        price_range=price_range_case
    ).values(
        'price_range'
    ).annotate(
        total_count=Count('id'),
        total_sales=Sum('price'),
        avg_price=Avg('price')
    ).order_by('price_range')
    
    # 转换为字典格式,方便业务使用
    return {item['price_range']: {
        'total_count': item['total_count'],
        'total_sales': item['total_sales'],
        'avg_price': item['avg_price']
    } for item in stats_queryset}

该方案直接生成优化后的SQL查询,数据库高效完成分组计算,返回结果已包含所有统计指标。


注意事项

  • 统一价格区间的边界逻辑,比如明确100元属于哪个区间,避免统计重复或遗漏
  • 若你的price字段未设置decimal_places,务必补充该参数,否则会影响数值存储与计算
  • 可根据业务需求在查询中添加filter条件,比如只统计特定分类、状态的产品

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:27:06