2009-11-30 35 views
1

我在找的是一個包含任何未加標籤的對象的QuerySet。用django-tagging檢索未加標籤的對象

我來了這麼遠的解決方案看起來過於複雜的對我說:

# Get all tags for model 
tags = Location.tags.all().order_by('name') 

# Get a list of tagged location id's 
tag_list = tags.values_list('name', flat=True) 
tag_names = ', '.join(tag_list) 
tagged_locations = Location.tagged.with_any(tag_names) \ 
            .values_list('id', flat=True) 

untagged_locations = [] 
for location in Location.objects.all(): 
    if location.id not in tagged_locations: 
     untagged_locations.append(location) 

任何想法需要改進?謝謝!

回答

3

有一個在這個帖子一些有用的信息,所以我不認爲它應該被刪除,但有一個非常非常簡單的解決方案

我快速瀏覽了django-tagging的源代碼。看起來他們使用ContentType框架和泛型關係來實現它。

正因爲如此,你應該能夠創建自己的位置類generic reverse relation獲得輕鬆前往TaggedItem對象爲給定的位置,如果你還沒有這樣做:

from django.contrib.contenttypes import generic 
from tagging.models import TaggedItem 

class Location(models.Model): 
    ... 

    tagged_items = generic.GenericRelation(TaggedItem, 
              object_id_field="object_id", 
              content_type_field="content_type") 

    ... 

澄清

我原來的答覆建議要做到這一點:

untagged_locs = Location.objects.filter(tagged_items__isnull=True) 

雖然該W烏爾德工作了「正常參與」,這其實並不在這裏,因爲內容類型框架拋出的content_type_id額外的檢查,到SQL爲isnull工作:

SELECT [snip] FROM `sotest_location` 
LEFT OUTER JOIN `tagging_taggeditem` 
ON (`sotest_location`.`id` = `tagging_taggeditem`.`object_id`) 
WHERE (`tagging_taggeditem`.`id` IS NULL 
AND `tagging_taggeditem`.`content_type_id` = 4) 

您可以通過反轉像劈周圍這個:

untagged_locs = Location.objects.exclude(tagged_items__isnull=False) 

但是,這不太對勁。

我也提出過這個,但是有人指出annotations don't work as expected與內容類型框架有關。

from django.db.models import Count 
untagged_locs = Location.objects.annotate(
    num_tags=Count('tagged_items')).filter(num_tags=0) 

上面的代碼對我的作品在我有限的測試案例,但它可能是越野車,如果你有你的模型等「加標籤」的對象。原因是它不檢查the ticket中概述的content_type_id。它生成以下SQL:

SELECT [snip], COUNT(`tagging_taggeditem`.`id`) AS `num_tags` 
FROM `sotest_location` 
LEFT OUTER JOIN `tagging_taggeditem` 
ON (`sotest_location`.`id` = `tagging_taggeditem`.`object_id`) 
GROUP BY `sotest_location`.`id` HAVING COUNT(`tagging_taggeditem`.`id`) = 0 
ORDER BY NULL 

如果Location是你唯一的加標籤的對象,那麼上面會工作。

建議解決方法

短期獲得註釋的工作機制的,這裏就是我會在此期間做到:

untagged_locs_e = Location.objects.extra(
     where=["""NOT EXISTS(SELECT 1 FROM tagging_taggeditem ti 
INNER JOIN django_content_type ct ON ti.content_type_id = ct.id 
WHERE ct.model = 'location' 
    AND ti.object_id = myapp_location.id)"""] 
) 

這增加了額外的WHERE子句中的SQL:

SELECT [snip] FROM `myapp_location` 
WHERE NOT EXISTS(SELECT 1 FROM tagging_taggeditem ti 
INNER JOIN django_content_type ct ON ti.content_type_id = ct.id 
    WHERE ct.model = 'location' 
    AND ti.object_id = myapp_location.id) 

它加入到django_content_type表中以確保您正在查看適當的 您的模型的內容類型在您有多個標籤模型類型的情況下。

更改myapp_location.id以匹配您的表名稱。可能有一種方法可以避免對錶名進行硬編碼,但是如果對你很重要,你可以弄清楚。

如果您不使用MySQL,請相應地進行調整。

+0

'object \ _id \ _field'和'content \ _type \ _field'參數在這裏是沒有意義的,因爲它們完全默認正在傳遞的內容,但是我覺得包括它們會有助於展示API。 – 2009-11-30 19:20:31

+0

感謝您提供一個很好的答案!然而,我可能做錯了什麼,但我無法讓它工作。我可以得到'Location.objects.filter(tagged_items__isnull = False)'給我一組帶標籤的項目,但是'Location.objects.filter(tagged_items__isnull = True)'只是給了我一個空的查詢集合。 – lemonad 2009-11-30 22:55:25

+0

另外,註釋真的可以正常使用泛型關係嗎?下面的票據表明它沒有:http://code.djangoproject.com/ticket/10461 – lemonad 2009-11-30 23:03:48

0

試試這個:

[location for location in Location.objects.all() if location.tags.count() == 0] 
+0

使用括號而不是方括號來獲得一臺發電機,而不是一個列表。 (大多數情況下)使用率相同,內存要求要低得多 – Javier 2009-11-30 19:14:01

+0

嗯,這是一個沒有標記的對象列表,但它不是未標記的對象的** queryset **。關鍵的區別在於它沒有管理員功能,也不會被懶惰地評估。 – 2009-11-30 19:53:05

0

假設您的Location類使用tagging.fields.TagField實用程序。

from tagging.fields import TagField 
class Location(models.Model): 
    tags = TagField() 

你可以只是這樣做:

Location.objects.filter(tags='') 
+0

不幸的是,django-tagging沒有引入'標籤'列,因此它可以在過濾器中使用。無論如何,不​​是對我來說......我想我已經根據「手冊」設置了一切。 – lemonad 2009-12-01 16:59:36

+0

我通過自己的一個簡單的django-tagging示例發現了這個問題,但我想你必須使用'TagField'實用程序才能將它包含在模型中。 – 2009-12-01 17:06:54

+0

啊哈,我可以看到這是如何工作的。我有'TagField',但不幸的是,如果您使用標記註冊模型,則不能將其命名爲'tags'。我遇到了一些非常醜陋的bug(標籤在使用TaggedItem等檢索時被刪除)。更改名稱後,一切正常。 我在這裏找到了重命名的建議:http://tylerlesmann.com/2009/mar/06/adding-tagging-django-10-applications-existing-dat/ – lemonad 2009-12-01 18:04:12