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
}
)
i tried chat gpt - but failed.
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?