2012-03-23 2 views
3

У меня есть запрос, содержащий некоторые объекты. В зависимости от некоторых случаев или другого я теперь хочу, чтобы исключить все объекты без определенных тегов (_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) 

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

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

ответ

0

Как описано в комментарии к ответу Криса, django-tagging не доставляет tagstring при доступе к 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) 

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

3

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

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

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

Также вы не можете получить доступ к полю _tags непосредственно в шаблоне. Имена полей, начинающиеся с подчеркивания, не допускаются. Я бы рекомендовал не начинать имя с подчеркивания – Mikael

+0

Спасибо за ваш быстрый ответ. Вы были абсолютно правы в аргументах запроса, но это не решает мою проблему. _tags вызывается так, как это происходит потому, что на модели есть свойство, называемое тегами, к которым гораздо проще получить доступ из шаблона;) – marue

2

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

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

Хорошо, спасибо. Я бы давно переключился на taggit, но я, к сожалению, застрял с другими приложениями, используя теги ... Кстати, что такое Q? Заполнитель? – marue

+1

'Q' - это просто объект, который инкапсулирует аргументы запроса. Он существует, чтобы разрешать сложные запросы с использованием OR и нетрадиционных AND и т. Д. Смотрите: https: //docs.djangoproject.com/en/dev/topics/db/queries/#complex-lookups-with-q –

+0

Еще одна вещь Я просто понял: к сожалению, django-tagging не доставляет tagstring при доступе к 'model._tags'. Похоже, создание TagField - это еще один способ регистрации модели как тега. Так что даже это решение не работало :( – marue

Смежные вопросы