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
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