2011-03-29 50 views
0

您好,我似乎遇到查詢問題。我有一個項目列表。任何物品都可以設置爲它的狀態(進出,收集,銷燬等)。這是我的看法。查詢使用過濾條件查找相關表格中最近的條目

def client_summary(request, client_id): 
    client = None 
    items = None 
try: 
    client = models.Client.objects.get(pk = client_id) 
    items = client.storageitem_set.all() 
    total_items = items.count() 
    except: 
     return HttpResponse(reverse(return_clients)) 
    return render_to_response('client_summary.html', {'items':items, 'total_items':total_items, 'client':client}, context_instance = RequestContext(request)) 

如果我有我的模板

{%for item in items%} 
     {{item.itemstatushistory_set.latest}} 
{%endfor%} 

這將顯示所有的最新狀態。現在我只想打印出狀態爲「僅銷燬」的所有項目。出於某種原因,我似乎無法做到這一點。

以下是我的模型的一些更多信息。

class StorageItem(models.Model): 
    type = models.ForeignKey(StorageObject) 
    client = models.ForeignKey(Client) 
    company_id = models.PositiveIntegerField(unique = True, blank = True, null = True) 
    content = models.TextField(blank = True) 
    alternative_id = models.CharField(verbose_name = 'Client no.', max_length = 60, blank = True) 
    title = models.CharField(max_length = 100) 
    format = models.ForeignKey(Format, blank = True, null = True) 
    location = models.CharField(max_length = 20, blank = True) 
    item_class = models.TextField(blank = True) 

    def __unicode__(self): 
     return self.title 

class Status(models.Model): 
    description = models.CharField(max_length = 60) 
    notes = models.TextField(blank = True) 
    def __unicode__(self): 
     return self.description 

    class Meta: 
     verbose_name_plural = 'Status' 
     get_latest_by = 'date' 
     ordering = ['date'] 

class ItemStatusHistory(models.Model): 
    date = models.DateTimeField(auto_now = True) 
    contact = models.ForeignKey(Contact) 
    item = models.ForeignKey(StorageItem) 
    status = models.ForeignKey(Status) 
    user = models.ForeignKey(User) 

    def __unicode__(self): 
     return str(self.status 

編輯:還有一些問題,因爲一個項目的關係可以有許多狀態。但是我只想列出最近的狀態僅用於銷燬物品。

示例:假設有3個項目,他們有套item1 = [in, out, destroyed]item2 = [destroyed, in]item3 = [destroyedcollected, destroyed]item4 = [in]其中[1st status, 2nd status, 3rd status, etc]。我只想顯示該項目的最新狀態。

Mike和kriegar都會得到類似[item1, item2, item3, item3]的結果。 由於Yuji使用了不同的功能,他將得到[item1, item2, item3]

我需要在最後得到的答案應該是[item1, item3]

+0

您是否在尋找* _only_ *已銷燬狀態的物品?或具有*任何*毀壞狀態的物品? – 2011-03-29 13:56:08

+0

@Yuji對於遲到的回覆感到抱歉。你的解決方案几乎是對的。但是,因爲用戶可以更改商品狀態,所以我只希望商品具有_destroyed_狀態,如果這有_latest status_。因此,一個物品可能會在一週內遭到破壞,但它的狀態會由用戶更改爲收集。一旦它的狀態改變了。它不應該在_destroyed_狀態列表中。你的代碼所做的是在任何項目中查找它是否具有_destroyed_狀態。然後打印。它應該只在_destroyed_是最新狀態時纔打印。 – Shehzad009 2011-03-29 14:42:08

回答

0

kriegar的解決方案將工作。還有這一條,這通過搜索狀態id而不是文本匹配上description

destroyedStatus = Status.objects.get(description="destroyed") 
clients_destroyed_items = StorageItem.objects.filter(client=client, 
    itemstatushistory__status=destroyedStatus) 

這是假設的描述是獨一無二的,但你必須在模型中沒有這樣的限制。我不知道哪個實現更快。

編輯:順便說一句,如果你有一些瘋狂的系統,你必須用「破壞」的描述不止一個狀態,你希望通過狀態id查詢s,而不是description,你會只是做:

destroyedStatusIDs = Status.objects.filter(description="destroyed").values_list("id", flat=True) 
clients_destroyed_items = StorageItem.objects.filter(client=client, 
    itemstatushistory__status__in=destroyedStatusIDs) 

順便說一句,它被認爲是很好的做法,設定related_nameForeignKeyOneToOneFieldManyToManyField關係,通常是複數。所以,你的歷史課變成:

class ItemStatusHistory(models.Model): 
    date = models.DateTimeField(auto_now=True) 
    contact = models.ForeignKey(Contact, related_name="history") 
    item = models.ForeignKey(StorageItem, related_name="history") 
    status = models.ForeignKey(Status, related_name="history") 
    user = models.ForeignKey(User, related_name="history") 

這將我的第一個例子改爲:

destroyedStatus = Status.objects.get(description="destroyed") 
clients_destroyed_items = StorageItem.objects.filter(client=client, 
    history__status=destroyedStatus) 

編輯2:啊,所以你只需要考慮當前的(即最新的)狀態。這是aggregationF objects進來的地方。基本上,這個想法是讓數據庫在表格中創建一個具有最新(即最大date)狀態的date的「僞列」,然後要求日期匹配以及狀態:

from django.db.models import F, Max 

destroyedStatus = Status.objects.get(description="destroyed") 
clients_destroyed_items = StorageItem.objects.annotate(
    last_change_date=Max("itemstatushistory__date")).filter(client=client, 
    itemstatushistory__status=destroyedStatus, 
    itemstatushistory__date=F("last_change_date")) 

我沒有測試過這一點,這是我第一次嘗試了這一點,有可能是一個更好的辦法,使意見是值得歡迎的。

+0

我一直在使用related_name,因爲我喜歡用implict來表示。 – DTing 2011-03-29 14:12:24

+0

我似乎得到一個錯誤消息''狀態'對象沒有任何屬性'values_list'' – Shehzad009 2011-03-29 15:18:46

+0

哎呀,忘了把'get'改成'filter'。固定。 – 2011-03-29 15:22:00

0

如果你想要一個屬於客戶端和被破壞的項目的查詢集:跨越relationships¶

的Django提供了一個功能強大,直觀 辦法「遵循

clients_destroyed_items = StorageItem.objects.filter(client=client, 
    itemstatushistory__status__description='destroyed') 

查找「 查找中的關係,自動爲您處理SQL JOINs ,在 場景後面。要跨越關係,只需 使用跨模型的相關字段 的字段名稱,用雙下劃線 分隔,直到您到達所需的 字段。

本示例檢索所有條目 對象與博客的名字是 '披頭士博客':

Entry.objects.filter(blog_ _exact = '披頭士 博客' )

這種跨越可以像你想象的那樣深。

它也向後工作。要引用 「反向」關係,只需使用模型的小寫名稱 。

+1

或'client.storageitem_set.filter(itemstatushistory__status__description ='Destroyed')。distinct()'並且順便說一句,當沒有設置related_name時,默認的查詢字段名不包含'_set',所以它只是' itemstatushistory__status__description' – 2011-03-29 13:49:42

+0

「順便說一下,當沒有設置related_name時,默認的查詢字段名稱不包含_set,所以它只是itemstatushistory__status__description」...這與文檔相矛盾:[「如果模型具有ForeignKey,實例的外鍵模型將有權訪問管理器,該管理器返回第一個模型的所有實例。默認情況下,此管理器名爲FOO_set,其中FOO是源模型名稱,小寫。「](http://docs.djangoproject .com/en/dev/topics/db/queries /#backwards-related-objects) – 2011-03-29 13:53:50

+0

當我累了的時候,我真的不應該回答問題。 =) – DTing 2011-03-29 14:01:06