如何在models.py中获取最新的外键值

时间:2015-08-21 09:50:06

标签: django

我在django应用程序中获取最新的外键值有点问题。这是我的两个模型:

class Stock(models.Model):
    ...

class Dividend(models.Model):
    date = models.DateField('pay date')
    stock = models.ForeignKey(Stock, related_name="dividends")
    class Meta:
        ordering = ["date"]

我想从股票对象中获得最新的股息。基本上就是这个 - stock.dividends.latest('date')。但是,每当我调用stock.dividends.latest('date')时,它都会激活sql查询以获得最新的红利。我有每个库存的循环中的latest()方法。我想避免这些SQL查询。我可以在class Stock中以某种方式定义新方法,以便在库存对象的sql查询中获得最新的红利吗? 我无法更改" date"的默认排序。到" -date"。
使用select_related('dividends')加载股票对象,但最新可能使用order_by,无论如何它都需要sql查询。 :(

EDIT1 :为了更清楚我想要的,这是一个例子。让我们说我在shares.keys()中有100个符号:

for stock in Stock.objects.filter(symbol__in=shares.keys()): # 1 sql query
    latest_dividend = stock.dividends.latest('date')                    # 100 sql queries
    ... #do something with latest dividend

好吧,在某些情况下,我可能在shares.keys()中有500个符号。这就是为什么我需要避免在获得股票的最新股息时进行SQL查询。

5 个答案:

答案 0 :(得分:0)

我不确定我的解决方案是最好的,但在这里(仅适用于PostgreSQL):

stocks = list(Stock.objects.filter(**something))
dividends = Dividend.objects.filter(
    stock__in=stocks,
).order_by(
    'stock_id',
    '-date'
).distinct(
    'stock_id',
)

dividends_dict = {d.stock_id: d for d in dividends}

for stock in stocks:
    stock.latest_dividend = dividends_dict.get(stock.id)

答案 1 :(得分:0)

我对你的问题感到有些困惑,我假设你试图从你的股票对象中获取股息,以便将你的查询限制在数据库中。我认为这是可能的最少数量查询。

 stock_options = stock.objects.get(pk=your_query)
 order_options = stock.dividend_set.order_by('-date')[:5]

答案 2 :(得分:0)

喜欢:谢谢你的回答。但我想我可以避免初始化那个大字典(我有5000股票和28万股股息)。但是你的清单给了我一个想法。您的代码需要2个SQL查询。这是我的例子(EDIT1)。

for stock in Stock.objects.filter(symbol__in=shares.keys())\
                          .prefetch_related('dividends'): # 2 sql queries
    latest_dividend = list(stock.dividends.all())[-1]     # 0 sql queries
    ... #do something with latest_dividend

我的代码也需要2个sql查询,但我不需要重新排序它并从股票和所有28万股息创建列表(我只在每个周期创建当前股票股息的dict)。可能创建一个dict比创建len(shares.keys())dicts更快,不确定。

我认为会有更简单的解决方案(避免从股息创建列表/字典),但现在这已经足够了。谢谢你的回答!

答案 3 :(得分:0)

我也遇到同样的问题,因此我测试了许多Django查询。终于,我发现我们可以使用这个:

Stock.objects.all().annotate(latest_date=Max('dividends__date')).filter(dividends__date=F('latest_date')).values('dividends')

答案 4 :(得分:0)

只要我了解您可以通过以下方式做到这一点:

stock.dividends.last()

因为在Django中的实现是这样的:

    def first(self):
    """Return the first object of a query or None if no match is found."""
    for obj in (self if self.ordered else self.order_by('pk'))[:1]:
        return obj

此外,您也可以使用.latest(*fields, field_name=None)