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

登录时按Collection统计Rating≤1数量并更新Purchased字段的问题

解决按Collection统计并更新Purchased的books_to_discard字段问题

我来帮你搞定这个问题!你的原代码有两个核心问题:一是把当前用户所有rating≤1的Rating总数统一赋值给了所有Purchased对象(甚至可能包含其他用户的),二是完全没按每个Purchased关联的Collection来区分统计。下面给你两种可行的解决方案:

方案一:基础遍历更新(适合数据量较小的场景)

修改你的discard视图如下:

from django.http import HttpResponse
from purchased_collections.models import Purchased
from rating.models import Rating

def discard(request):
    # 只获取当前登录用户的Purchased记录,避免修改其他用户的数据
    user_purchased = Purchased.objects.filter(user=request.user)
    
    # 准备批量更新的对象列表
    update_list = []
    
    for purchased in user_purchased:
        # 精准统计当前Purchased对应的Collection下,当前用户rating≤1的Rating数量
        discard_count = Rating.objects.filter(
            user=request.user,
            rating__lte=1,
            # 通过Book模型关联到当前Purchased的Collection
            book__collection=purchased.collection
        ).count()
        
        purchased.books_to_discard = discard_count
        update_list.append(purchased)
    
    # 批量更新,比逐个调用save()更高效
    Purchased.objects.bulk_update(update_list, ['books_to_discard'])
    
    return HttpResponse("已按Collection完成丢弃书籍数量更新")

代码解释:

  • 首先过滤出当前用户的所有Purchased记录,确保不会修改其他用户的数据
  • 遍历每个Purchased对象时,通过book__collection=purchased.collection这个关联查询,精准锁定当前Collection下的书籍对应的Rating
  • 统计符合rating≤1且属于当前用户的记录数,赋值给对应Purchased的books_to_discard
  • 最后用bulk_update批量保存,减少数据库IO操作,比循环调用object.save()性能更好

方案二:高效批量统计(适合数据量较大的场景)

如果你的用户有大量Purchased和Rating记录,上面的遍历会产生多次数据库查询,推荐用这种方式减少查询次数:

from django.http import HttpResponse
from django.db.models import Count
from purchased_collections.models import Purchased
from rating.models import Rating

def discard(request):
    # 一次查询统计当前用户每个Collection下rating≤1的记录数
    collection_discard_stats = Rating.objects.filter(
        user=request.user,
        rating__lte=1
    ).values('book__collection').annotate(
        discard_count=Count('id')
    ).values('book__collection', 'discard_count')
    
    # 转成字典,方便快速查找:Collection ID -> 对应统计数
    count_map = {item['book__collection']: item['discard_count'] for item in collection_discard_stats}
    
    # 获取当前用户的所有Purchased记录
    user_purchased = Purchased.objects.filter(user=request.user)
    
    update_list = []
    for purchased in user_purchased:
        # 从字典中取对应Collection的统计数,没有符合条件的记录则设为0
        purchased.books_to_discard = count_map.get(purchased.collection.id, 0)
        update_list.append(purchased)
    
    Purchased.objects.bulk_update(update_list, ['books_to_discard'])
    
    return HttpResponse("已高效完成丢弃书籍数量更新")

代码解释:

  • 先用annotate和values做一次聚合查询,直接统计出当前用户每个Collection下符合条件的Rating数量,只需要一次数据库查询
  • 把统计结果转成字典,后续可以在内存中快速匹配每个Purchased对应的Collection的统计数
  • 最后同样用bulk_update批量保存,整体数据库查询次数从N+1次(N为Purchased数量)降到2次,性能提升明显

原代码的问题复盘

  1. 未限定用户范围:原代码中purchased.update(...)没有过滤用户,会修改系统中所有Purchased对象的数据,这是非常危险的
  2. 未按Collection区分:直接统计当前用户所有rating≤1的总数,没有关联每个Purchased对应的Collection,导致所有Purchased的books_to_discard值都一样

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:09:23