Django category count, print can't filtered

i want to solve django category problem

i want print out, counting as category data.

for example

  • python (3)

  • html (2)

but result

how can i solve? i will send my codes

# models.py

from django.db import models
from django.contrib.auth.models import User

import os

class Category(models.Model):
    name = models.CharField(max_length=50, unique=True)
    slug = models.SlugField(max_length=200, unique=True, allow_unicode=True)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return f"/blog/category/{self.slug}/"
    

    # admin 단에서의 이름을 설정
    class Meta:
        verbose_name_plural = "categories"


class Post(models.Model):
    title = models.CharField(max_length=30)
    # 후킹해주는 메세지 100글자 한도로 노출
    hook_text = models.CharField(max_length=100, blank=True)
    content = models.TextField()

    # auto_now=True를 해주면, 추가로 입력해줄 것 없이, 해당되는 내용이 자동 등록 된다.
    # settings에 MEDIA_URL, MEDIA_ROOT로 넣어주었던 주소 뒤로 어떻게 해줄지를 말해준다.
    head_image = models.ImageField(upload_to="blog/images/%Y/%m/%d/", blank=True)
    file_upload = models.FileField(upload_to="blog/files/%Y/%m/%d/", blank=True)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    # CASCADE는 연결되어있는 값도 같이 삭제 해준다는 뜻
    # SET_NULL은 해당 값을 삭제해도, 해당 pk 값은 공백으로 두되, 나머지 데이터는 살려두는 것
    # blank=True를 해줘야 카테고리 미 추가시 오류가 뜨지 않는다.
    author = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
    category = models.ForeignKey(Category, null=True, blank=True, on_delete=models.SET_NULL)
    tags = models.ManyToManyField(Tag, blank=True)

    # 이걸로써, 관리자 단에서 내용을 보게 되면 작성된 텍스트로 표시된다.
    def __str__(self):
        return f"[{self.pk}]{self.title} :: {self.author}"

    def get_absolute_url(self):
        return f"/blog/{self.pk}/"

    def get_file_name(self):
        return os.path.basename(self.file_upload.name)
    
    def get_file_ext(self):
        return self.get_file_name().split(".")[-1]
# urls.py

from django.urls import path
from . import views

urlpatterns = [
    # path("", views.index),
    path("", views.PostList.as_view()),
    # path("<int:pk>/", views.single_post_page),
    path("<int:pk>/", views.PostDetail.as_view()),
    path("category/<str:slug>/", views.category_page),
    path("tag/<str:slug>/", views.tag_page),
    path("create_post/", views.PostCreate.as_view())
]
# views.py

from django.shortcuts import render, redirect
from django.views.generic import ListView, DetailView, CreateView
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from .models import Post, Category

class PostList(ListView):
    model = Post
    ordering = "-pk"
    # template_name = "blog/index.html"

    def get_context_data(self, **kwargs):
        context = super(PostList, self).get_context_data()
        context["categories"] = Category.objects.all()
        context["no_category_post_count"] = Post.objects.filter(category=None).count()
        # context["category"] = None
        return context
        

class PostDetail(DetailView):
    model = Post

    def get_context_data(self, **kwargs):
        context = super(PostDetail, self).get_context_data()
        context["categories"] = Category.objects.all()
        context["no_category_post_count"] = Post.objects.filter(category=None).count()
        return context

class PostCreate(LoginRequiredMixin, CreateView):
    model = Post
    fields = ["title", "hook_text", "content", "head_image", "file_upload", "category"]

    def form_valid(self, form):
        current_user = self.request.user
        if current_user.is_authenticated:
            form.instance.author = current_user
            return super(PostCreate, self).form_valid(form)
        else:
            return redirect("/blog/")
      


def category_page(request, slug):
    if slug == "no_category":
        category = None
        post_list = Post.objects.filter(category=None)
    else:
        category = Category.objects.get(slug=slug)
        post_list = Post.objects.filter(category=category)

    return render(
        request,
        "blog/post_list.html",
        {
            "post_list": post_list,
            "categories": Category.objects.all(),
            "no_category_post_count": Post.objects.filter(category=None).count(),
            "category": category
        }
    )
  1. i tried chat gpt - but failed.

  2. i tried category conbining parts looked - but failed

You can use the annotate() method along with the Count aggregation function of the Django ORM to find and store the number of objects stored in the QuerySet.

from django.db.models import Count
...
"categories": Category.objects.annotate(post_count=Count('post')),

The Count('post') aggregates the number of Post objects related to each Category through the ForeignKey. Then you may refer to your own annotation, post_count, in your templates:

<ul>
    {% for category in categories %}
        <li>
            <a href="{{ category.get_absolute_url }}">{{ category.name }}</a>
            ({{ category.post_count }} posts)
        </li>
    {% endfor %}
</ul>

Don't worry about the replacement of the all() method, there's no difference really - What is difference between objects.all().annotate and objects.annotate?

Вернуться на верх