2015-06-06 116 views
0

我已經提出了與此問題相關的上一篇文章here,但因爲這是一個相關的,但新的問題我認爲最好是爲它製作另一篇文章。Django ORM - 左加入與WHERE子句

我使用Django 1.8

我有一個用戶模型和UserAction模型。用戶有一個類型。 UserAction有一段時間,表示動作持續了多長時間,還有一個start_time指示動作何時開始。他們是這樣的:

class User(models.Model): 
    user_type = models.IntegerField() 

class UserAction: 
    user = models.ForeignKey(User) 
    time = models.IntegerField() 
    start_time = models.DateTimeField() 

現在我想要做的就是給定類型和他們的行動,可選擇由START_TIME過濾的時間的總和的所有用戶。

什麼我做的是這樣的:

# stubbing in a start time to filter by 
start_time = datetime.now() - datetime.timedelta(days=2) 
# stubbing in a type 
type = 2 
# this gives me the users and the sum of the time of their actions, or 0 if no 
# actions exist 
q = User.objects.filter(user_type=type).values('id').annotate(total_time=Coalesce(Sum(useraction__time), 0) 
# now I try to add the filter for start_time of the actions to be greater than or # equal to start_time 
q = q.filter(useraction__start_time__gte=start_time) 

現在是什麼這樣做當然是內連接上UserAction的,從而消除所有的用戶,無需操作。我真正想要做的就是將我的LEFT JOIN與WHERE子句相提並論,但對於我來說,我無法找到如何去做。我查看了文檔,查看了源代碼,但沒有找到答案。我(很漂亮)確定這是可以完成的事情,我只是沒有看到如何。任何人都可以將我指向正確的方向嗎?任何幫助將非常感激。非常感謝!

+0

沒有用途的用戶應該包含在結果中嗎? – f43d65

+0

@ f43d65 - 是的,他們應該 – TheMethod

回答

0

我和你有同樣的問題。我還沒有找到任何解決問題的方法,但我找到了一些修復方法。

  • 一種方式是通過所有的用戶進行循環:但是

    q = User.objects.filter(user_type=type) 
    for (u in q): 
        u.time_sum = UserAction.filter(user=u, start_time__gte=start_time).aggregate(time_sum=Sum('time'))['time_sum'] 
    

    這種方法確實在數據庫中的每個用戶的查詢。如果你沒有很多用戶,它可能會訣竅,但如果你有一個龐大的數據庫可能會花費很多時間。

  • 解決該問題的另一種方法是使用QuerySet API的extra方法。這是Timmy O'Mahony在this blog post中詳細描述的一種方法。

    valid_actions = UserAction.objects.filter(start_time__gte=start_time) 
    q = User.objects.filter(user_type=type).extra(select={ 
        "time_sum": """ 
        SELECT SUM(time) 
        FROM userAction 
        WHERE userAction.user_id = user.id 
        AND userAction.id IN %s 
        """ % (%s) % ",".join([str(uAction.id) for uAction in valid_actions.all()]) 
    }) 
    

    但是,這種方法依賴於調用與SQL表名的數據庫,這是非常不Django的 - 如果你改變你的數據庫的一個或它們的列之一db_columndb_table,這段代碼將不再工作。它雖然只需要2個查詢,第一個獲得有效的userAction列表,另一個將它們總結爲匹配的用戶。