How change a function based view into a class based?

I want to write a category detail view in order to do so i want to change this function based view

def CategoryView(request, cats):
category_posts = Post.objects.filter(category=cats.replace('-', ' '))
return render(request, 'categories.html', {'cats':cats.replace('-', ' ').title(), 'category_posts':category_posts})

into the class based view. My first question: 1. How to do so?; 2.How also change the url for the view?;

path('category/<str:cats>/', CategoryView, name='category'),

Here is my models:

from django.conf import settings
from django.db import models
from django.urls import reverse

class Category(models.Model):
    name = models.CharField(max_length=255)

    def __str__(self):
        return (self.name)

    def get_absolute_url(self):
         return reverse("home")


class Post(models.Model):
    title = models.CharField(max_length=255)
    body = models.TextField()
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    category = models.ManyToManyField(Category, related_name='categories')

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse("post_detail", kwargs={"pk": self.pk})

    @property
    def categories(self):
        return ', '.join([x.name for x in self.category.all()])

class Comment(models.Model): 
    article = models.ForeignKey(Post, null=True, blank=True, on_delete=models.CASCADE)
    comment = models.CharField(max_length=140)
    author = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,)

    def __str__(self):
        return self.comment

    def get_absolute_url(self):
        return reverse("post_list")

When you write an answer, if you don’t mind, can you also write an explanation a step by step. And can you also write how did you figure out the answer. A lost a useful materials would be also helpful. Thank you in advance

>Solution :

You url shall look like :

path('category/<str:cats>/', CategoryClassView.as_view(), name='category')

Since in your case, you want to render ‘html’, below is example class view

#in your views.py

from django.views.generic import TemplateView

class CategoryClassView(TemplateView):
    template_name = "categories.html"
    def get_context_data(self, **kwargs):
        cats = kwargs.get("cats")
        category_posts = Post.objects.filter(category=cats.replace('-', ' '))
        context = {'cats':cats.replace('-', ' ').title(), 'category_posts':category_posts}
        return context

To answer your second part regarding how did I figure it out. Most of the the logic you have written in your function based view would be used as it, only thing you need to figure out apt attribute and method to overide. Checkout basic concept of python-inheritance and just figure out the attributes/method of particular class you want to overide. Documentation is always a good start for it.

Leave a Reply