登录时按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次,性能提升明显
原代码的问题复盘
- 未限定用户范围:原代码中
purchased.update(...)没有过滤用户,会修改系统中所有Purchased对象的数据,这是非常危险的 - 未按Collection区分:直接统计当前用户所有
rating≤1的总数,没有关联每个Purchased对应的Collection,导致所有Purchased的books_to_discard值都一样
内容的提问来源于stack exchange,提问作者Felipe
相关产品推荐
相关产品推荐

