Search code examples
pythondjangotemplatesdjango-viewstagging

How to output the name of the current tag to the template? (The one we are in)


I'm trying to display the name of the current tag, i.e. the one we are in. Does not work. How to write correctly to display a tag in a template?

        #Models

        from django.db import models
        from taggit.managers import TaggableManager


        class Blog(models.Model):
            title = models.CharField(max_length=150)
            created_at = models.DateTimeField(auto_now_add=True)
            description = models.CharField(max_length=550)
            tags = TaggableManager()
    
            def __str__(self):
                return self.title


        #Views

        from django.shortcuts import render
        from django.views.generic import ListView
        from .models import *
        from taggit.models import Tag


        class TagMixin(object):
              def get_context_data(self, **kwargs):
                  context = super(TagMixin, self).get_context_data(**kwargs)
                  context['tags'] = Tag.objects.all()
                  return context

        class PostIndexView(TagMixin,ListView):
            model = Blog
            template_name = 'blog.html'
            queryset=Blog.objects.all()
            context_object_name = 'posts'

        class TagIndexView(TagMixin,ListView):
            model = Blog
            template_name = 'blog.html'
            context_object_name = 'posts'

            def get_queryset(self):
                return Blog.objects.filter(tags__slug=self.kwargs.get('tag_slug'))


        #Templates

        {% if tag %}
             <h3>Posts by tag: {{ tag }}</h3>  <!-- Does not display tag name -->
        {% endif %}

        

P.s. The site asks for more description, but what else can be described here? The problem with the output is described


Solution

  • if i correct understand - you dont have any tag variable in your template. You have tags. In this case:

    #Templates
    {% for tag in tags %}
        <h3>Posts by tag: {{ tag }}</h3>
    {% endfor %}
    

    if you want to have a special tag_slug in context - you should add it in context manually, as you do it with tags. Or you can use this construction:

    #Templates
    {% if view.kwargs.tag_slug %}
        <h3>Posts by tag: {{ view.kwargs.tag_slug }}</h3>
    {% endif %}
    

    Also if You want have only 1 current tag you should filter it:

    class TagMixin(object):
        def get_context_data(self, **kwargs):
            context = super(TagMixin, self).get_context_data(**kwargs)
            context['tags'] = Tag.objects.all()
            context['tag'] = Tag.objects.filter(slug=self.kwargs.get('tag_slug', '')).first()
            return context
    

    By the way __str__ should always return str type. Direct conversion in string is preferable:

    class Blog(models.Model):
        def __str__(self):
            return f'{self.title}'
    

    In new Python you can concatenate dicts and you can have empty super and Classes are by default children from object:

    class TagMixin:
          def get_context_data(self, **kwargs):
              return super().get_context_data(**kwargs) | {'tags' : Tag.objects.all()}
    

    For generic ListView you dont need to define both queryset and model. One of them is enough. Define queryset is couple microseconds faster then model. Also you don't need to override the template name and context_object_name. Simply use default blogs_list and blogs_app/blogs_list.html

    class PostIndexView(TagMixin,ListView):
        queryset=Blog.objects.all()
        # Thats all, you dont need any other attributes