Reputation: 23
I'm new in django and generally in programming. And now I write my first project - that will be my personal blog, it's almost done except one feature: I have list of categories shown on the page in the right panel.
1) The question is how can I sort/filter my posts by these categories? I mean I want to click on one of these categories in the right panel and to see the posts where that category is mentioned (post may have several categories).
I've tried a lot of combinations, which found on stackoverflow, but I didn't do that before so can't understand how to realize that feature in my project.
models.py
class Category(models.Model):
title = models.CharField(max_length=20)
def __str__(self):
return self.title
class Post(models.Model):
title = models.CharField(max_length=100)
overview = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
content = HTMLField('Content')
author = models.ForeignKey(Author, on_delete=models.CASCADE)
thumbnail = models.ImageField()
categories = models.ManyToManyField(Category)
featured = models.BooleanField()
previous_post = models.ForeignKey('self', related_name='previous', on_delete=models.SET_NULL, blank=True, null=True)
next_post = models.ForeignKey('self', related_name='next', on_delete=models.SET_NULL, blank=True, null=True)
def __str__(self):
return self.title
views.py
def filter_by_category(request):
post_list = Post.objects.filter(categories=)
context = {
'post_list': post_list
}
return render(request, 'post_by_category.html', context)
urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('', index),
path('blog/', blog, name='post-list'),
path('search/', search, name='search'),
path('blog/filter_by_category/', filter_by_category, name='filter_by_category'),
path('subscribe/', email_list_signup, name='subscribe'),
path('create/', post_create, name='post-create'),
path('post/<id>/', post, name='post-detail'),
path('post/<id>/update/', post_update, name='post-update'),
path('post/<id>/delete/', post_delete, name='post-delete'),
path('tinymce/', include('tinymce.urls')),
path('accounts/', include('allauth.urls')),
sidebar.html
<div class="widget categories">
<header>
<h3 class="h6">Categories</h3>
</header>
{% for cat in category_count %}
<div class="item d-flex justify-content-between">
<a href="{% url 'filter_by_category' %}">{{ cat.categories__title }}</a><span>{{ cat.categories__title__count }}</span></div>
{% endfor %}
</div>
Given code doesn't work, I know that the problem in views.py. I'm absolutely messed up how to write it correctly. Help me please to solve this problem.
UPDATED: It's solved, thanks a lot to Landcross. I was close in some moments to that decision, but messed up. Thank you!
Upvotes: 2
Views: 338
Reputation: 492
First, expand your url definition like so:
path('blog/filter_by_category/<str:category>', filter_by_category, name='filter_by_category'),
Now you are defining a variable named 'category' (which is a string, hence the str) in the url which can be passed to the view:
def filter_by_category(request, category):
post_list = Post.objects.filter(categories__title=category)
context = {
'post_list': post_list
}
return render(request, 'post_by_category.html', context)
And change your template so it adds the parameter to the url:
<div class="widget categories">
<header>
<h3 class="h6">Categories</h3>
</header>
{% for cat in category_count %}
<div class="item d-flex justify-content-between">
<a href="{% url 'filter_by_category' category=cat.categories__title %}">{{ cat.categories__title }}</a><span>{{ cat.categories__title__count }}</span></div>
{% endfor %}
</div>
You can also change the url to int and change your template to use the category ID instead of title if that's something you like more or works better for you (e.g. if category titles can contain duplicates).
Upvotes: 4