首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用django-tagging检索未标记的对象

使用django-tagging检索未标记的对象
EN

Stack Overflow用户
提问于 2009-12-01 02:50:39
回答 3查看 693关注 0票数 1

我要找的是一个包含所有未加标签的对象的QuerySet。

到目前为止,我想出的解决方案对我来说过于复杂了:

代码语言:javascript
复制
# 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)

有什么改进的想法吗?谢谢!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-12-01 03:16:17

在这篇文章中有一些很好的信息,所以我不认为应该删除它,但有一个简单得多的解决方案

我快速浏览了一下django-tagging的源代码。看起来他们使用了ContentType框架和泛型关系来实现。

因此,您应该能够在location类上创建generic reverse relation,以便轻松访问给定位置的TaggedItem对象(如果您还没有这样做的话):

代码语言:javascript
复制
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")

    ...

澄清

我最初的回答是这样做的:

代码语言:javascript
复制
untagged_locs = Location.objects.filter(tagged_items__isnull=True)

虽然这可以用于“普通连接”,但实际上在这里不起作用,因为内容类型框架在isnull的SQL中抛出了对content_type_id的额外检查:

代码语言:javascript
复制
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 )

你可以像这样颠倒它来绕过它:

代码语言:javascript
复制
untagged_locs = Location.objects.exclude(tagged_items__isnull=False)

但这感觉不太对劲。

我也提出了这一点,但有人指出,annotations don't work as expected与内容类型框架。

代码语言:javascript
复制
from django.db.models import Count
untagged_locs = Location.objects.annotate(
    num_tags=Count('tagged_items')).filter(num_tags=0)

上面的代码适用于我有限的测试用例,但是如果你的模型中有其他“可加标签”的对象,它可能会有but。原因是它不会检查the ticket中概述的content_type_id。它生成了以下SQL:

代码语言:javascript
复制
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是您唯一可加标签的对象,那么上面的方法将起作用。

建议的解决方法

除了让注解机制正常工作外,我现在要做的是:

代码语言:javascript
复制
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)"""]
)

这将向SQL添加一个额外的WHERE子句:

代码语言:javascript
复制
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,请进行相应的调整。

票数 3
EN

Stack Overflow用户

发布于 2009-12-01 03:10:20

试试这个:

代码语言:javascript
复制
[location for location in Location.objects.all() if location.tags.count() == 0]
票数 0
EN

Stack Overflow用户

发布于 2009-12-02 00:50:20

假设您的Location类使用tagging.fields.TagField实用程序。

代码语言:javascript
复制
from tagging.fields import TagField
class Location(models.Model):
    tags = TagField()

你可以这样做:

代码语言:javascript
复制
Location.objects.filter(tags='')
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1821658

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档