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

Django多表关联优化查询:特定店铺月度Deal分性别浏览量统计

优化Django查询:高效统计店铺当月Deal的分性别浏览次数

嘿,我来帮你搞定这个查询优化的问题!你的当前代码确实存在N+1数据库查询的问题——嵌套循环里每次访问seg.deal_view和x.client都会触发新的数据库请求,当Deal或浏览量多的时候,性能会直线下降。咱们用Django ORM的聚合查询来一次性搞定所有统计,只需要一次数据库访问。

问题分析

原代码的逻辑是:先获取店铺→获取店铺下的Deal→过滤当月的浏览记录→循环每个Deal→再循环每个浏览记录获取用户性别。这会导致:

  • 每个Deal都要单独查询对应的浏览记录
  • 每个浏览记录又要单独查询用户的性别
  • 大量重复的数据库请求,性能极低

优化方案:一次性聚合统计

根据你的需求,分两种场景给出优化代码:

场景1:统计整个店铺当月所有Deal的总浏览量(按性别分组)

如果需要知道整个店铺里,男性、女性、其他性别的用户分别浏览了多少次Deal,用这个查询:

from django.db.models import Count
from datetime import datetime, timedelta

# 计算近30天的日期范围(和原代码逻辑一致)
end_date = datetime.now().date()
start_date = end_date - timedelta(days=30)

# 一次性查询并统计分性别浏览次数
gender_view_stats = deals_view.objects.filter(
    # 关联到目标店铺的Deal
    deal__store_id=storeid,
    # 筛选当月的浏览记录
    date_added__range=(start_date, end_date)
).values(
    # 按用户性别分组
    'client__gender'
).annotate(
    # 统计每个性别的浏览次数
    view_count=Count('id')
).order_by('-view_count')  # 可选:按浏览次数降序排列

返回的gender_view_stats是一个QuerySet,每个元素是类似这样的字典:

[
    {'client__gender': 'M', 'view_count': 45},
    {'client__gender': 'F', 'view_count': 32},
    {'client__gender': 'O', 'view_count': 8}
]

场景2:统计每个Deal的分性别浏览次数

如果需要知道店铺里每个具体Deal对应的不同性别浏览量,用这个查询:

deal_gender_stats = deals_view.objects.filter(
    deal__store_id=storeid,
    date_added__range=(start_date, end_date)
).values(
    # 按Deal和性别分组,带上Deal的ID和标题方便识别
    'deal__id', 'deal__title', 'client__gender'
).annotate(
    view_count=Count('id')
).order_by('deal__id')

返回结果示例:

[
    {'deal__id': 1, 'deal__title': "夏季促销", 'client__gender': 'M', 'view_count': 18},
    {'deal__id': 1, 'deal__title': "夏季促销", 'client__gender': 'F', 'view_count': 12},
    {'deal__id': 2, 'deal__title': "新品折扣", 'client__gender': 'F', 'view_count': 20}
]

处理性别为Null的情况

如果有些用户没有设置性别(gender字段为null),可以用Coalesce将null转为统一的标识(比如'Unknown'):

from django.db.models.functions import Coalesce

gender_view_stats = deals_view.objects.filter(
    deal__store_id=storeid,
    date_added__range=(start_date, end_date)
).annotate(
    # 将null性别转为'Unknown'
    normalized_gender=Coalesce('client__gender', 'Unknown')
).values(
    'normalized_gender'
).annotate(
    view_count=Count('id')
)

为什么这个优化有效?

  • 原代码是多次零散查询,而优化后的查询利用Django ORM的JOIN操作,一次性关联deals_view、deals、client_profile、stores四张表,筛选+分组统计一步完成。
  • 只需要一次数据库请求就能拿到所有统计数据,彻底解决N+1问题,性能提升非常明显,尤其是数据量较大的时候。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:03:04