Как искать объекты без определенных тегов? - PullRequest
3 голосов
/ 23 марта 2012

У меня есть набор запросов, содержащий несколько объектов. В зависимости от того или иного случая я теперь хочу исключить все объекты без определенных тегов (_tags - это имя TagField на моей модели):

self.queryset=self.queryset.exclude(_tags__id__in=avoid)

Но это просто оставляет меня с ошибкой:

Caught FieldError while rendering:
Join on field '_tags' not permitted.
Did you misspell 'id' for the lookup type?

Поскольку я почти уверен, что не ошибся в «id», я провел некоторый поиск того, как использовать тегирование для чего-то подобного. В документах много о пользовательских менеджерах, но почему-то я просто не могу понять, как я могу использовать их, чтобы получить то, что я хочу.

редактирование:

исправил код выше до

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

где избежать - список целых чисел. И это оставляет меня с проблемой, что TagField django-tagging - это просто специальный CharField (или TextField?). Который, конечно, не будет ничего сортировать, если я просто запросить его по списку целых чисел. Я мог бы попытаться решить это так:

for tag in avoid:
    self.queryset=self.queryset.exclude(_tags__contains=tag.name)

, который не только уродлив, но и оставляет меня с проблемой тегов, составленных из нескольких слов или соответствующих частей других тегов.

У меня почему-то есть подозрение, что кто-то, кто понял, как работает django-tagging, может решить эту проблему намного красивее.

Ответы [ 3 ]

3 голосов
/ 23 марта 2012

Как определяются ваши модели? Является ли _tags полем ForeignKey?

если не удалить часть __id

self.queryset=self.queryset.exclude(_tags__in=avoid)
2 голосов
/ 23 марта 2012

К сожалению, нет, красивее нет.На самом деле, реальное решение еще страшнее, но когда все теги хранятся в одном текстовом поле, другого пути нет:

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)

В приведенном выше коде предполагается, что теги разделены пробелами.Если нет, вам придется изменить код, чтобы он соответствовал их разделению.Идея состоит в том, что вы используете разделитель как часть поиска, чтобы убедиться, что это фактический тег, а не просто часть другого тега.

Если вы не хотите делать это таким образом, я бы предложилпереключение на другую систему тегов, которая не выводит их все в одно текстовое поле, например django-taggit .

0 голосов
/ 24 марта 2012

Как описано в комментарии к ответу Криса, django-tagging не доставляет строку тега при доступе к model._tag. В конце концов, у меня не было другого решения, кроме как сделать запрос и впоследствии разобрать циклы, содержащие определенный тег:

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)

Чтобы завершить, модель для этого выглядит следующим образом:

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)

Несмотря на то, что я довольно долго пытался это сделать, я не нашел способа связать запрос с тегами в цепочке запросов для объекта. Для этого проекта я застрял с тегами, но это реальный недостаток ...

...