2010-02-04 40 views
2

我有兩個模型LocationEvent,它們通過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) 
+1

發佈您的嘗試代碼和原始SQL比較 – Pentium10 2010-02-04 10:19:43

+0

@Gary - 我現在還沒有時間,但這絕對是肯定可能的,在Django的ORM中 - 不要放入原始SQL中。如果沒有人幫助你,我會盡量在後面發表一個答案。 – 2010-02-04 10:34:24

回答

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]) 

並返回到模板中呈現。

直到您對它進行基準測試並證明它是您的應用程序的瓶頸之前,請不要忽視它。

0

我想你應該看看Django的聚集link text,所以你的結果會因位置與條件來agragated過濾未來/過期事件和分鐘(START_TIME)返回下一個事件的時間

1
select id, (
    select * from event 
    where location=location.id 
    and start_date>NOW() 
    order by start_date asc 
    limit 1 
    ) 
from location 
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) 

分享和享受。