我有两个模型Location
和Event
,它们由Event
模型上的ForeignKey链接。模型分解如下:
class Location(models.Model):
city = models.CharField('city', max_length=25)
slug = models.SlugField('slug')
class Event(models.Model):
location = models.ForeignKey(Location)
title = models.CharField('title', max_length=75)
start_date = models.DateTimeField('start_date')
end_date = models.DateTimeField('end_date')
每个位置都有多个按start_date
降序排序的事件。我正在尝试的查询检索每个位置的下一个即将发生的事件。
理想情况下,我想在单个查询中进行此操作(我不想为每个位置运行查询,因为这会导致对数据库进行大量不必要的命中)。我尝试过使用Django的ORM,我也尝试过使用原始SQL,但是我遇到了一些障碍。
非常感谢任何帮助。
更新
我想出了一个潜在的解决方案,尽管我不相信这是最好的方法。它的工作原理应该足够了,但我很想知道这样做的最佳方法是什么。
无论如何,我写的代码如下:
l = Location.objects.select_related()
qs = None
# Concatenate the related event querysets into a new queryset
for e in l:
if qs is None:
qs = e.event_set.all()
else:
qs = qs | e.event_set.all()
# Order a slice of the queryset by start_date ascending
qs = sorted(qs[:l.count()], key=lambda s: s.start_date)
答案 0 :(得分:1)
select id, (
select * from event
where location=location.id
and start_date>NOW()
order by start_date asc
limit 1
)
from location
答案 1 :(得分:1)
“理想情况下,我想在单个查询中进行此操作(我不想为每个位置运行查询,因为这会导致对数据库进行大量不必要的命中)。”
这是一个错误的假设。
1)Django的ORM使用缓存。它可能不会像您想象的那样经常查询数据库。数据库有一个缓存。查询的成本可能不是您的想法。
2)你有select_related
。 ORM可以为您进行联接。 http://docs.djangoproject.com/en/dev/ref/models/querysets/#id4
只需编写最简单的循环来获取位置和事件。在极不可能的情况下,这是您应用程序中最慢的部分(并且您可以证明它是最慢的),然后添加select_related
并查看改进程度。
在您能够证明此特定查询正在查杀您的应用程序之前,请继续前进,不要担心“点击数据库”。
每个地点的下一个活动?
[ l.event_set.order_by( start_date ).all()[0] for l in Location.objects.select_related().all() ]
或者
events = []
for l in Location.objects.select_related().all():
events.append( l.event_set.order_by( start_date ).all()[0] )
将其返回到要渲染的模板。
在对基准进行基准测试并证明它是您应用程序的瓶颈之前,请不要忽视这一点。
答案 2 :(得分:0)
我认为您应该查看django aggregation link text,因此您的结果将按位置进行格式化,条件是过滤未来/过期事件,min(start_time)返回下一个事件时间
答案 3 :(得分:0)
以下内容可能有用:
SELECT * FROM EVENTS V
WHERE (V.LOCATION, V.START_DATE) IN
(SELECT E.LOCATION, MIN(E.START_DATE)
FROM EVENTS E
WHERE E.START_DATE >= NOW
GROUP BY E.LOCATION)
分享并享受。