Search code examples
pythondjangodjango-taggit

Django tag detail page with taggit


I've a very similar problem like this post. Long story short, I've got a django blog, and for tags I'm using django-taggit which is working nice on the admin page.

AdminScreen

My main problem is that if I like to filter to a tag by an url address I still receive a 404 error although I red the documentation and couple of stackoverflow post:

Page not found (404) Request Method: GET Request URL: http://127.0.0.1:8080/tag/sample/

views.py

from django.utils import timezone
from .models import Post
from django.shortcuts import render, get_object_or_404
from taggit.models import Tag


def post_list(request):
    posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
    return render(request, 'blog/post_list.html', {'posts': posts})


def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'blog/post_detail.html', {'post': post})


def tag_detail(request, tag):
    tag = get_object_or_404(Tag, tag=tag)
    return render(request, 'blog/tag_detail.html', {'tag': tag})

urls.py(app)

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.post_list, name='post_list'),
    url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail, name='post_detail'),
    url(r'^tag/(?P<tag>[-/w]+)/$', views.tag_detail, name='tag_detail'),
]

models.py

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


class Post(models.Model):
    author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
    title = models.CharField(max_length=200)
    text = models.TextField()
    created_date = models.DateTimeField(
            default=timezone.now)
    published_date = models.DateTimeField(
            blank=True, null=True)

    tags = TaggableManager()

    def ttags(self):
        return [t.name for t in self.tags.all()]

    def publish(self):
        self.published_date = timezone.now()
        self.save()

    def __str__(self):
        return self.title


class Tag(models.Model):
    name = models.CharField(max_length=200)

    def __unicode__(self):
        return self.name

I'm surely know that I miss something (maybe something simple) just can't figure it out what it is. How can I fix this issue? Thank you for help in advance.


Solution

  • I manage to fix the taggit tagging issue, although it's more like a look than document or other based solution.

    models.py

    from django.db import models
    from django.utils import timezone
    from taggit.managers import TaggableManager
    
    
    class Post(models.Model):
        author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
        title = models.CharField(max_length=200)
        text = models.TextField()
        created_date = models.DateTimeField(
                default=timezone.now)
        published_date = models.DateTimeField(
                blank=True, null=True)
    
        tags = TaggableManager()
    
        def publish(self):
            self.published_date = timezone.now()
            self.save()
    
        def __str__(self):
            return self.title
    

    ursl.py

    from django.conf.urls import url
    from . import views
    
    urlpatterns = [
        url(r'^$', views.post_list, name='post_list'),
        url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail, name='post_detail'),
        url(r'^tag/(?P<tag>\w+)/$', views.tag_detail, name='tag_detail'),
    ]
    

    It's pretty self-explanatory until then.

    views.py

    from django.utils import timezone
    from .models import Post
    from django.shortcuts import render, get_object_or_404
    
    
    def post_list(request):
        posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
        return render(request, 'blog/post_list.html', {'posts': posts})
    
    
    def post_detail(request, pk):
        post = get_object_or_404(Post, pk=pk)
        return render(request, 'blog/post_detail.html', {'post': post})
    
    
    def tag_detail(request, tag):
        posts = Post.objects.filter(tags__slug=tag)
        return render(request, 'blog/tag_detail.html', {"posts": posts, "tag": tag})
    

    So in the tag_detail def I'm using filtering tags__slug=tag. My only main issue about this (although it's working perfectly) than I found this solution by plain luck, I didn't find anything about in the django documentation field lookup section nor in the taggit documentation.

    Before I forget the html file of the tag result page:

    {% extends 'blog/base.html' %}
    {% block content %}
    <h2>Posts tagged: {{tag}}</h2>
    {% for post in posts %}
    <p>{{ post.published_date }}: <a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a></p>
    {% endfor %}
    {% endblock %}    
    

    If anyone has idea why and how is this working please, let me know.