我在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查询。
答案 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)
。