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

如何通过Django QuerySet基于日期和股票代码关联两个模型?

问题描述

在Django中有两张表,分别存储股票数据(ohlcdata模型)和股票元数据(BulkData模型),每个模型中date与ticker的组合具有唯一性。模型定义如下:

class BulkData(models.Model):
    date = models.DateField()    
    ticker = models.CharField(max_length=10)
    name = models.CharField(max_length=400)
    type = models.CharField(max_length= 20)
    exchange_short_name = models.CharField(max_length=5)
    MarketCapitalization = models.DecimalField(max_digits=40, decimal_places=2)
    request_exchange = models.CharField(max_length=20)
   

class ohlcdata(models.Model):
    
    date = models.DateField()
    ticker = models.CharField(max_length=10, null=False)

    open = models.DecimalField(max_digits=15, decimal_places=5, null = True)
    high = models.DecimalField(max_digits=15, decimal_places=5, null = True)
    low = models.DecimalField(max_digits=15, decimal_places=5, null = True)
    close = models.DecimalField(max_digits=15, decimal_places=5, null = True)
    volume = models.DecimalField(max_digits=40, decimal_places=0, null = True)

需要基于date和ticker字段执行左连接操作,目前使用原生SQL查询:

query3 = "SELECT * FROM stocklist_bulkdata LEFT JOIN stocklist_ohlcdata ON `stocklist_bulkdata`.`date` = `stocklist_ohlcdata`.`date` AND `stocklist_bulkdata`.`ticker` = `stocklist_ohlcdata`.`ticker` WHERE `stocklist_bulkdata`.`date` = '2023-03-30'"

qs3 = BulkData.objects.raw(query3)

希望改用Django QuerySet实现该操作。

解决方案

由于两个模型未定义外键关联,可通过以下两种方式实现基于date和ticker的左连接查询:

方法1:使用Subquery+Annotate(无需修改模型)

通过子查询将ohlcdata的字段作为注释字段附加到BulkData查询集,模拟左连接效果:

from django.db.models import Subquery, OuterRef

# 定义子查询,匹配当前BulkData的date和ticker
ohlc_subquery = ohlcdata.objects.filter(
    date=OuterRef('date'),
    ticker=OuterRef('ticker')
).values(
    'open', 'high', 'low', 'close', 'volume'
)[:1]

# 构建目标QuerySet,筛选指定日期并关联ohlc数据
qs = BulkData.objects.filter(date='2023-03-30').annotate(
    ohlc_open=Subquery(ohlc_subquery.values('open')),
    ohlc_high=Subquery(ohlc_subquery.values('high')),
    ohlc_low=Subquery(ohlc_subquery.values('low')),
    ohlc_close=Subquery(ohlc_subquery.values('close')),
    ohlc_volume=Subquery(ohlc_subquery.values('volume'))
)

查询后可通过obj.ohlc_open、obj.ohlc_high等属性访问对应股票数据,无匹配记录时返回None,与左连接行为一致。

方法2:添加复合外键关联(长期推荐方案)

若允许修改模型,建议给ohlcdata添加基于date+ticker的复合外键关联,后续查询会更简洁:

修改模型定义

from django.db.models import UniqueConstraint

class BulkData(models.Model):
    date = models.DateField()    
    ticker = models.CharField(max_length=10)
    name = models.CharField(max_length=400)
    type = models.CharField(max_length= 20)
    exchange_short_name = models.CharField(max_length=5)
    MarketCapitalization = models.DecimalField(max_digits=40, decimal_places=2)
    request_exchange = models.CharField(max_length=20)

    class Meta:
        constraints = [
            UniqueConstraint(fields=['date', 'ticker'], name='unique_date_ticker')
        ]

class ohlcdata(models.Model):
    bulk_data = models.ForeignKey(
        BulkData,
        on_delete=models.CASCADE,
        related_name='ohlc_data',
        null=True,
        blank=True
    )
    date = models.DateField()
    ticker = models.CharField(max_length=10, null=False)

    open = models.DecimalField(max_digits=15, decimal_places=5, null = True)
    high = models.DecimalField(max_digits=15, decimal_places=5, null = True)
    low = models.DecimalField(max_digits=15, decimal_places=5, null = True)
    close = models.DecimalField(max_digits=15, decimal_places=5, null = True)
    volume = models.DecimalField(max_digits=40, decimal_places=0, null = True)

    class Meta:
        constraints = [
            UniqueConstraint(fields=['date', 'ticker'], name='ohlc_unique_date_ticker')
        ]

执行数据库迁移后,使用select_related查询

qs = BulkData.objects.filter(date='2023-03-30').select_related('ohlc_data')

此时可通过obj.ohlc_data.open直接访问对应股票数据,无匹配记录时obj.ohlc_data为None。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 08:57:13