Исключить некоторые сообщения из подсчета тегов

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

My models.py:

from taggit.managers import TaggableManager

class Post(models.Model):
    ...
    tags = TaggableManager(blank=True)

My template.html:

{% load taggit_templatetags2_tags %}

  {% get_taglist as tags for 'blog.post' %}

  {% for tag in tags %}
    {% if tag.slug != 'draft' and tag.slug != 'retired' %}
      <h4 style="text-align:center"><a href="{% url 'blog:post_list_by_tag' tag.slug %}">
        {{ tag }} ({{ tag.num_times }}) </a></h4>
    {% endif %}
  {% endfor %}

Но я хочу исключить из подсчета все теги черновых сообщений и удаленных сообщений. Я хочу исключить не только теги «черновик» и «пенсионер» (я уже делаю это), но и другие теги, которые могут быть у таких постов. Как я могу это сделать?

Например, у меня есть два поста. У первого есть только тег «собака». Второй имеет теги «собака» и «черновик». Это черновик, пост еще не опубликован.

Мой код дал бы: собака (2), потому что он подсчитывает теги всех сообщений. Когда пользователь нажмет на «собаку», появится страница со всеми опубликованными сообщениями с тегом собаки, поэтому в нашем случае это одно сообщение, потому что второе не опубликовано. Пользователь спросит себя: там два собачьих поста, а где второй? Это нехорошо. Также я не хочу намекать на аргументацию постов, которые скоро будут опубликованы.

Вероятно, мне придется возиться с кодом taggit_templatetags2...

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

Вот код taggit_templatetags2:

@register.tag
class GetTagList(TaggitBaseTag):
    name = 'get_taglist'

    def get_value(self, context, varname, forvar, limit=settings.LIMIT, order_by=settings.TAG_LIST_ORDER_BY):
        # TODO: remove default value for limit, report a bug in the application
        # django-classy-tags, the default value does not work
        queryset = get_queryset(
            forvar,
            settings.TAGGED_ITEM_MODEL,
            settings.TAG_MODEL)
        queryset = queryset.order_by(order_by)
        context[varname] = queryset
        if limit:
            queryset = queryset[:limit]
        return ''

def get_queryset(forvar, taggeditem_model, tag_model):
    through_opts = taggeditem_model._meta
    count_field = (
        "%s_%s_items" % (
            through_opts.app_label,
            through_opts.object_name)).lower()

    if forvar is None:
        # get all tags
        queryset = tag_model.objects.all()
    else:
        # extract app label and model name
        beginning, applabel, model = None, None, None
        try:
            beginning, applabel, model = forvar.rsplit('.', 2)
        except ValueError:
            try:
                applabel, model = forvar.rsplit('.', 1)
            except ValueError:
                applabel = forvar
        applabel = applabel.lower()

        # filter tagged items
        if model is None:
            # Get tags for a whole app
            queryset = taggeditem_model.objects.filter(
                content_type__app_label=applabel)
            tag_ids = queryset.values_list('tag_id', flat=True)
            queryset = tag_model.objects.filter(id__in=tag_ids)
        else:
            # Get tags for a model
            model = model.lower()
            if ":" in model:
                model, manager_attr = model.split(":", 1)
            else:
                manager_attr = "tags"
            model_class = get_model(applabel, model)
            if not model_class:
                raise Exception(
                    'Not found such a model "%s" in the application "%s"' %
                    (model, applabel))
            manager = getattr(model_class, manager_attr)
            queryset = manager.all()
            through_opts = manager.through._meta
            count_field = ("%s_%s_items" % (through_opts.app_label,
                                            through_opts.object_name)).lower()

    if count_field is None:
        # Retain compatibility with older versions of Django taggit
        # a version check (for example taggit.VERSION <= (0,8,0)) does NOT
        # work because of the version (0,8,0) of the current dev version of
        # django-taggit
        try:
            return queryset.annotate(
                num_times=Count(settings.TAG_FIELD_RELATED_NAME))
        except FieldError:
            return queryset.annotate(
                num_times=Count('taggit_taggeditem_items'))
    else:
        return queryset.annotate(num_times=Count(count_field))

куда:

queryset = manager.all() дает список всех тегов

count_field это строка: taggit_taggeditem_items

queryset.annotate(num_times=Count(count_field)) — набор запросов с дополнительным полем num_times,


person fabio    schedule 01.02.2018    source источник


Ответы (2)


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

    queryset.exclude(slug__in=['черновик', 'выведен из эксплуатации'])

  • вы также можете попробовать использовать метод values для подсчета количества вхождений вашего тега. если я правильно понял, попробуйте:

    queryset.values('id').annotate(num_times=Count(count_field))

person Ghariani Mohamed    schedule 01.02.2018
comment
Спасибо за вашу помощь, но я боюсь, что ваш код мне сейчас не поможет. Я работаю с двумя внешними приложениями (taggit и taggit_templatetag), поэтому я не знаю, где найти набор запросов или как их перехватить. Кроме того, для эффективного исключения этих тегов из набора запросов тегов полезно, но мой приоритет состоит в том, чтобы исключить сообщение с этими тегами из набора запросов сообщений, используемого для подсчета тегов... если я могу это сделать, мне не нужно подсчитывать теги , taggit_templatetag мне подойдет. Тем не менее, если я решу не использовать это приложение, ваш код будет полезен. Я отредактировал свой пост, чтобы добавить пример - person fabio; 02.02.2018

Итак, вот то, что я сделал, без taggit_template_tags2, вероятно, можно оптимизировать, пожалуйста!

My model.py:

class Post(models.Model):
    ...
    tags = TaggableManager(blank=True)

My views.py:

...
#filter the posts that I want to count
tag_selected = get_object_or_404(Tag, slug='ritired')
posts = Post.objects.filter(published_date__lte=timezone.now()).exclude(tags__in=[tag_selected])
#create a dict with all the tags and value=0
tag_dict = {}
tags=Post.tags.all()
for tag in tags:
    tag_dict[tag]=0
#count the tags in the post and update the dict
for post in posts:
    post_tag=post.tags.all()
    for tag in post_tag:
        tag_dict[tag]+=1
#delete the key with value=0
tag_dict = {key: value for key, value in tag_dict.items() if value != 0}
#pass the dict to the template
context_dict={}
context_dict['tag_dict']=tag_dict
return render(request, 'blog/post_list.html', context_dict)

My template.html:

  {% for key, value in tag_dict.items %}
    <h4 style="text-align:center"><a href="{% url 'blog:post_list_by_tag' key.slug %}">
      {{ key }} ({{ value }})
    </h4>
  {% endfor %}

Быстро и легко!

person fabio    schedule 02.02.2018