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

不使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 04:39:05