不使用select_related基于多列关联两个Django模型并计算加权和
解决方案
完全可以在数据库层面一次完成关联查询和加权计算,不需要先拉两份数据到本地再用pandas合并,性能更好,也能减少不必要的数据传输开销,以下是两种常用实现方案:
方案1:直接使用原生SQL查询(最直观,适配所有Django版本)
直接构造内连接的SQL语句,用Django的raw()方法执行,同时可以直接在SQL里完成加权和的计算:
# 如需先拿到每行的四个字段:data_date、asset_id、weight、return query_sql = """ SELECT r.data_date, r.asset_id, w.weight, r.return FROM `return` r INNER JOIN `weight` w ON r.data_date = w.data_date AND r.asset_id = w.asset_id WHERE r.data_date >= %s AND r.data_date <= %s AND r.asset_id IN %s """ # 代入参数执行查询 merged_data = AssetReturnTs.objects.raw(query_sql, [start_date, end_date, tuple(asset_list)]) # 如要直接计算每个日期的收益率加权和,修改SQL用聚合即可: sum_sql = """ SELECT r.data_date, SUM(r.return * w.weight) as weighted_return FROM `return` r INNER JOIN `weight` w ON r.data_date = w.data_date AND r.asset_id = w.asset_id WHERE r.data_date >= %s AND r.data_date <= %s AND r.asset_id IN %s GROUP BY r.data_date """ weighted_sum_result = AssetReturnTs.objects.raw(sum_sql, [start_date, end_date, tuple(asset_list)])
你可以直接遍历merged_data拿到每行的四个字段,也可以转成字典格式,和你之前用ORM查出来的结果格式完全兼容。
方案2:使用Django ORM的FilteredRelation(Django 2.0+支持,不需要写原生SQL)
如果你不想写原生SQL,也可以用ORM自带的关联方法实现,不需要额外给模型加外键:
from django.db.models import F, FilteredRelation, Q, Sum # 关联两个表,拿到四个字段的结果 merged_queryset = AssetReturnTs.objects.filter( data_date__range=(start_date, end_date), asset_id__in=asset_list ).annotate( weight_info=FilteredRelation( 'asset__assetweightts', # 两个模型都关联了Asset表,通过Asset反向关联权重表 condition=Q(asset__assetweightts__data_date=F('data_date')) ) ).filter( weight_info__isnull=False # 等效于内连接,过滤掉没有匹配权重的数据 ).values( 'data_date', 'asset_id', weight=F('weight_info__weight'), return=F('return') ) # 如需直接计算每日加权和,新增聚合逻辑即可 weighted_sum = merged_queryset.annotate( daily_weighted_return=Sum(F('return') * F('weight')) ).values('data_date', 'daily_weighted_return')
注:如果你的Asset模型中给AssetWeightTs的外键没有自定义
related_name,那么默认反向关联名称为assetweightts_set,请对应替换asset__assetweightts为asset__assetweightts_set即可。
这个方案完全用ORM语法实现,不需要硬编码表名、字段名,后续如果模型有修改,维护成本更低。
两种方案都只会执行一次数据库查询,比你之前先查两份数据再用pandas合并的性能好很多,尤其是数据量较大的时候优势会非常明显。
内容的提问来源于stack exchange,提问作者Shubham Periwal
相关产品推荐
相关产品推荐

