Python Django中如何按用户按日筛选最高奖励记录
在Django环境下筛选用户每日最高奖励记录
问题描述
给定一个包含用户奖励信息的字典列表,需要筛选出每个用户每日获得的最高奖励对应的完整记录。例如user_id=4在2022年9月9日有两条奖励记录,金额分别为45.00和95.00,需保留金额最高的95.00对应的记录。
输入示例:
import datetime my_list = [ {'id': 1, 'user_id': 4, 'date': datetime.datetime(2022, 9, 9), 'prize': '45.00'}, {'id': 2, 'user_id': 5, 'date': datetime.datetime(2022, 9, 5), 'prize': '85.00'}, {'id': 3, 'user_id': 5, 'date': datetime.datetime(2022, 9, 5), 'prize': '35.00'}, {'id': 4, 'user_id': 4, 'date': datetime.datetime(2022, 9, 9), 'prize': '95.00'}, {'id': 5, 'user_id': 3, 'date': datetime.datetime(2022, 9, 9), 'prize': '10.00'}, {'id': 6, 'user_id': 6, 'date': datetime.datetime(2022, 9, 5), 'prize': '15.00'} ]
期望输出:
result = [ {'id': 2, 'user_id': 5, 'date': datetime.datetime(2022, 9, 5), 'prize': '85.00'}, {'id': 4, 'user_id': 4, 'date': datetime.datetime(2022, 9, 9), 'prize': '95.00'}, {'id': 5, 'user_id': 3, 'date': datetime.datetime(2022, 9, 9), 'prize': '10.00'}, {'id': 6, 'user_id': 6, 'date': datetime.datetime(2022, 9, 5), 'prize': '15.00'} ]
解决方案
方案1:纯Python内存处理(适用于数据已加载到列表的场景)
如果数据已经是内存中的字典列表,可以通过两次遍历完成筛选:
- 先构建
(user_id, 日期)与最高奖励金额的映射关系 - 再次遍历原列表,筛选出符合最高金额的记录
import datetime my_list = [ {'id': 1, 'user_id': 4, 'date': datetime.datetime(2022, 9, 9), 'prize': '45.00'}, {'id': 2, 'user_id': 5, 'date': datetime.datetime(2022, 9, 5), 'prize': '85.00'}, {'id': 3, 'user_id': 5, 'date': datetime.datetime(2022, 9, 5), 'prize': '35.00'}, {'id': 4, 'user_id': 4, 'date': datetime.datetime(2022, 9, 9), 'prize': '95.00'}, {'id': 5, 'user_id': 3, 'date': datetime.datetime(2022, 9, 9), 'prize': '10.00'}, {'id': 6, 'user_id': 6, 'date': datetime.datetime(2022, 9, 5), 'prize': '15.00'} ] # 构建用户-日期对应的最高奖励映射 max_prize_map = {} for item in my_list: date_key = item['date'].date() # 提取日期部分,忽略时分秒 prize_val = float(item['prize']) key = (item['user_id'], date_key) # 更新最高奖励 if key not in max_prize_map or prize_val > max_prize_map[key]: max_prize_map[key] = prize_val # 筛选符合条件的记录 result = [] for item in my_list: date_key = item['date'].date() key = (item['user_id'], date_key) if float(item['prize']) == max_prize_map[key]: result.append(item) # 查看结果 print(result)
方案2:Django ORM查询(适用于数据来自数据库的场景)
如果数据存储在Django模型中,直接用ORM聚合查询更高效,无需加载全量数据到内存:
假设模型定义如下:
from django.db import models from django.utils import timezone class PrizeRecord(models.Model): user_id = models.IntegerField() date = models.DateTimeField(default=timezone.now) prize = models.DecimalField(max_digits=10, decimal_places=2)
方法A:分组聚合+筛选
from django.db.models import Max, F # 先获取每个用户每日的最高奖励金额 max_prizes = PrizeRecord.objects.values('user_id', 'date__date').annotate( max_prize=Max('prize') ) # 构造筛选条件,匹配(user_id, 日期, 最高奖励)的组合 filter_conditions = [ (item['user_id'], item['date__date'], item['max_prize']) for item in max_prizes ] # 筛选完整记录 result = PrizeRecord.objects.filter( **{ '(user_id, date__date, prize)__in': filter_conditions } ) # 转成字典列表 result_list = list(result.values('id', 'user_id', 'date', 'prize'))
方法B:子查询(更简洁)
from django.db.models import Subquery, OuterRef # 子查询:获取当前用户当前日期的最高奖励金额 subquery = PrizeRecord.objects.filter( user_id=OuterRef('user_id'), date__date=OuterRef('date__date') ).values('prize').annotate(max_prize=Max('prize')).values('max_prize') # 筛选奖励等于最高金额的记录 result = PrizeRecord.objects.filter(prize=Subquery(subquery)) result_list = list(result.values('id', 'user_id', 'date', 'prize'))
内容的提问来源于stack exchange,提问作者Munna
相关产品推荐
相关产品推荐

