2013-02-27 155 views
4

我想在Django中以最有效的方式做一個非常複雜的查詢,我不知道如何開始。我有這些模型(這是一個簡化版本)最有效的Django查詢返回結果跨越多個表

class Status(models.Model): 
    status = models.CharField(max_length=200) 

class User(models.Model): 
    name = models.CharField(max_length=200) 

class Event(models.Model): 
    user = models.ForeignKey(User) 

class EventItem(models.Model): 
    event = models.ForeignKey(Event) 
    rev1 = models.ForeignKey(Status, related_name='rev1', blank=True, null=True) 
    rev2 = models.ForeignKey(Status, related_name='rev2', blank=True, null=True) 
    active = models.BooleanField() 

我想創建一個查詢,將導致在其中的所有依賴EventItems有rev1rev2不爲空大多數的活動用戶的列表或者nulland active = True

我知道我可以通過用戶列表進行迭代,然後檢查他們的所有事件匹配rev1rev2active標準,然後返回這些事件做到這一點,但是這是沉重的數據庫上。有什麼建議麼?

謝謝!

回答

3

我想要創建一個查詢,它將生成一個用戶列表,其中的所有依賴EventItems的rev1和rev2不是空白或null,活動= True的事件數最多的用戶。

首先,你想Event總是有這種類型的對象EventItem

events = Event.objects.filter(active=True) 
events = events.exclude(eventitem__rev1__isnull=True) 
events = events.exclude(eventitem__rev1='') 
events = events.exclude(eventitem__rev2__isnull=True) 
events = events.exclude(eventitem__rev2='') 

另外,如果你想處理有沒有EventItemEvent對象未指定。您可以使用以下內容進行過濾:

events = events.exclude(eventitem__isnull=True) 

請注意events可能包含大量重複項。如果你願意的話,你可以扔events.distinct(),但是隻有在你需要它的時候纔可以閱讀。

一旦你擁有了這些,你現在可以提取想要的User對象:

users = User.objects.filter(event__in=events) 

注意,某些數據庫後端,*啊哈的MySQL啊哈*,你可能會發現.filter(field__in=QuerySet)模式really slow。對於這種情況,該代碼應該是:

users = User.objects.filter(event__in=list(events.values_list('pk', flat=True))) 

您然後可以通過連接Event對象的數量訂購的東西:

from django.db.models import Count 
active_users = users.annotate(num_events=Count('event')).order_by('-num_events') 
6

你的模型已經壞了,但是這應該總結出你正在以一種更清潔的方式做的事情。

class Status(models.Model): 
    status = models.CharField(max_length=200) 

class User(models.Model): 
    name = models.CharField(max_length=200) 
    events = models.ManyToManyField('Event') 

class Event(models.Model): 
    rev1 = models.ForeignKey(Status, related_name='rev1', blank=True, null=True) 
    rev2 = models.ForeignKey(Status, related_name='rev2', blank=True, null=True) 
    active = models.BooleanField() 

和查詢

User.objects.filter(events__active=True).exclude(Q(events__rev1=None)|Q(events__rev2=None)).annotate(num_events=Count('events')).order_by('-num_events')

這將返回用戶的列表,在其設定的事件數進行排序。

欲瞭解更多信息,請查看Many-To-Many字段。

+0

謝謝,羅馬,但它並沒有真正符合我的問題 - 我我沒有使用'ManyToMany'字段 - 任何想法我如何用我現有的模型做事。我最初忘記了'EventItem'中的'event'字段,但我補充說。謝謝! – 2013-02-28 01:04:13

+0

對於以「什麼是規劃我的模型......查詢類型的最佳方式」開頭的問題,這是一個很好的答案。 不幸的@JonoBacon沒有問這個問題。也許下次呢? – airtonix 2013-02-28 01:57:53

0

你可以嘗試這樣的:

EventItem.objects.exclude(rev1=None).exclude(rev2=None).filter(active=True).values_list('event__user', flat=True) 

這會給你的用戶ID的平面列表,每個ID的頻率是EventItem多少個對象是用戶。

您或許可以做得更好,並使用.annotate()將其集成到查詢中,但我不確定如何現在。