I have a strange behavior im my generic views. Below is the classic FBV scheme I want to reproduce in a CBV
My FBV
def post_list(request, tag_name=None):
if tag_name:
# filter post according to tag name if provided
posts = Post.objects.filter(tag__tag_name=tag_name)
else:
posts = Post.objects.all()
context = {"posts": posts}
return render(request, "blog/post_list.html", context)
def post_detail(request, post_id):
post = Post.objects.get(pk=post_id)
context = {"post": post}
return render(request, "blog/post_detail.html", context)
My CBV
class PostList(ListView):
model = Post
context_object_name = "post_list"
template_name = "blog/post_list.html"
def get_queryset(self):
if "tag_name" in self.kwargs:
return Post.objects.filter(tag__tag_name=self.kwargs["tag_name"])
else:
return Post.objects.all()
class PostDetail(DetailView):
model = Post
context_object_name = "post_detail"
template_name = "blog/post_detail.html"
Here are my models
from django.db import models
# Create your models here.
class Tag(models.Model):
tag_name = models.CharField(max_length=100)
def __str__(self):
return self.tag_name
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
tag = models.ManyToManyField(Tag, blank=True)
def __str__(self):
return self.title
And here my urls
from django.urls import path
from .views import PostList, PostDetail
urlpatterns = [
path("", PostList.as_view(), name="blog-index"),
path("<tag_name>", PostList.as_view(), name="blog-index"),
path("<int:pk>", PostDetail.as_view(), name="post-detail")
]
As you can see I want to use the same generic view for the list of my posts with an optional tag provided in url. It is well filtering my articles when I provide a url with a tag, something like this .../blog/my_tag
but problem is that the DetailView
process does not work anymore. It loads my blog/post_list.html
with empty list always instead of my blog/detail_post.html
template. The DetailView
process works well when I remove the process to filter with tag.
I hope this is clear enough. What I am doing wrong ?
CodePudding user response:
The url pattern is the problem here: All your detail view request are getting matched with Second path i.e: path("<tag_name>", PostList.as_view(), name="blog-index"), try to provide a path pattern with converters that they match as you want in your application.The sequence matters here as first match is first served.
Instead of this:
urlpatterns = [
path("", PostList.as_view(), name="blog-index"),
path("<tag_name>", PostList.as_view(), name="blog-index"),
path("<int:pk>", PostDetail.as_view(), name="post-detail")
]
You can differentiate by some prefixes and path converters so that they match the exact case as you want for example:
urlpatterns = [
path('postlist/', PostList.as_view(),name='blog-index'),
path('postlist/<str:tag_name>/', PostList.as_view(),name='blog-index-tag'),
path('postdetail/<int:pk>/', PostDetail.as_view(),name='post-detail'),
]