[Django]-How to search for objects without certain tags?

0👍

As described in the comment on Chris’ answer, django-tagging does not deliver the tagstring when accessing model._tag. In the end i had no other solution than to do the query and sort out the loops containing a certain tag afterwards:

itemlist = list(queryset)
avoid = some_list_of_tag_ids            
# search for loops that have NONE of the avoid tags
for item in itemlist:
    #    has tags   and [ if a tag.id in avoid this list has an element]
    if (item.tags)  and [tag for tag in item.tags if tag.id in avoid]:
        # remove the item from the list
        itemlist.remove(item)

To complete that the model for this looks like this:

class Item(models.Model):

    _tags = TagField(blank=True,null=True)

    def _get_tags(self):
        return Tag.objects.get_for_object(self)
    def _set_tags(self, tags):
        Tag.objects.update_tags(tags)

    tags = property(_get_tags, _set_tags)

Allthough i tried for quite a while, i found no way of chaining a query against tagging tags into a query chain for an object. For this project I’m stuck with tagging, but this is a real drawback…

👤marue

3👍

How are your models defined? Is _tags a ForeignKey field?

if not remove the __id part

self.queryset=self.queryset.exclude(_tags__in=avoid)
👤Mikael

2👍

Unfortunately, no, there’s no prettier way. In fact, the actual solution is even uglier, but when all the tags are stored in a single text field, there’s no other way:

from django.db.models import Q

startswith_tag = Q(_tags__startswith=tag.name+' ')
contains_tag = Q(_tags__contains=' '+tag.name+' ')
endswith_tag = Q(_tags__endswith=' '+tag.name)
self.queryset=self.queryset.exclude(startswith_tag | contains_tag | endswith_tag)

The code above assumes that tags are delimited with spaces. If not, you’ll have to modify the code to match how they are delimited. The idea is that you use the delimiter as part of the search to ensure that it’s the actual tag and not just part of another tag.

If you don’t want to do it this way, I’d suggest switching to another tag system that doesn’t dump them all into a single text field, django-taggit for instance.

Leave a comment