인프런 커뮤니티 질문&답변

몽상가님의 프로필 이미지

작성한 질문수

Do It! 장고+부트스트랩: 파이썬 웹개발의 정석

포스트 목록 페이지 수정하기 2

포스트 목록 페이지 수정하기2 중에서 막히는 부분이 있습니다. (미분류)

작성

·

383

·

수정됨

0

안녕하세요 선생님. 강의 열심히 듣고 있습니다^^;

다름이 아니라 아래와 같이 미분류 카운트가 입력되지 않아 오류가 발생하는 부분때문에 계속 찾아보았으나,

답답한 마음에 질문글을 남깁니다.

우선 카테고리 분류에서

프로그래밍, 문화&예술 까진 카운트가 잘 입력됩니다.

그렇지만 "미분류" 부분은 계속 () 으로 표시됩니다.

분명 미분류 부분이 존재함에도 불구하고, 카운트가 되지 않는 건 무엇이 잘못되었는지 도저히 알기가 어렵습니다. 혹시 확인이 가능할까요?^^;;

 

test.py 실행시 오류화면

미분류() 카운트 부분을 주석처리하면 테스트는 잘 완료됩니다.

총 4개의 페이지에 대한 코드를 올려봅니다.

  1. test.py

  2. base.html

  3. views.py

  4. post_list.html

 

test.py

from django.test import TestCase, Client
from django.contrib.auth.models import User
from bs4 import BeautifulSoup
from .models import Post, Category

# Create your tests here.

class TestView(TestCase):
    def setUp(self):
        self.client = Client()
        # 방문하는 사람의 브라우저다 Client()
        self.user_trump = User.objects.create_user(
            username='trump',
            password='somepassword'
        )
        self.user_obama = User.objects.create_user(
            username='obama',
            password='somepassword'
        )

        self.category_programming = Category.objects.create(
            name='programming', slug='programming'
        )

        self.category_music = Category.objects.create(
            name='music', slug='music'
        )

        self.post_001 = Post.objects.create(
            title='첫 번째 포스트입니다.',
            content='Hello, world, we are the world',
            category=self.category_programming,
            author=self.user_trump,
        )

        self.post_002 = Post.objects.create(
            title='두 번째 포스트입니다.',
            content='1등이 전부는 아니잖아요. 저는 개발을 좋아할겁니다.',
            category=self.category_music,
            author=self.user_obama,
        )
        self.post_003 = Post.objects.create(
            title='세 번째 포스트입니다.',
            content='Category 가 없을 수도 있죠.',
            author=self.user_obama,
        )

    def navbar_test(self, soup):
        navbar = soup.nav
        self.assertIn('Blog', navbar.text)
        self.assertIn('about_me', navbar.text)

        logo_btn = navbar.find('a', text='Do it Django')
        self.assertEqual(logo_btn.attrs['href'], '/')

        home_btn = navbar.find('a', text='Home')
        self.assertEqual(home_btn.attrs['href'], '/')

        blog_btn = navbar.find('a', text='Blog')
        self.assertEqual(blog_btn.attrs['href'], '/blog/')

        about_me_btn = navbar.find('a', text='about_me')
        self.assertEqual(about_me_btn.attrs['href'], '/about_me/')

    def category_card_test(self, soup):
        categories_card = soup.find('div', id='categories-card')
        self.assertIn('Categories', categories_card.text)
        self.assertIn(
            f'{self.category_programming} ({self.category_programming.post_set.count()})',
            categories_card.text
        )

        self.assertIn(
            f'{self.category_music} ({self.category_music.post_set.count()})',
            categories_card.text
        )

        self.assertIn(
             f'미분류 ({Post.objects.filter(category=None).count()})', categories_card.text
        )

    def test_post_list_with_posts(self):
        self.assertEqual(Post.objects.count(), 3)
        # 1.1 포스트 목록 페이지 (post_list)를 연다.
        response = self.client.get('/blog/')

        # 1.2 정상적으로 페이지가 로드된다.
        self.assertEqual(response.status_code, 200)

        # 1.3 페이지 타이틀에 Blog 라는 문구가 있다.
        soup = BeautifulSoup(response.content, 'html.parser')
        self.assertIn('Blog', soup.title.text)

        self.navbar_test(soup)
        self.category_card_test(soup)

        # 3-2. 포스트 목록 페이지를 새로 고침 했을 때,
        response = self.client.get('/blog/')
        soup = BeautifulSoup(response.content, 'html.parser')

        # 3-3. 메인영역에 포스트 2개의 타이틀이 존재한다.
        main_area = soup.find('div', id='main-area')
        self.assertNotIn('아직 게시물이 없습니다.', main_area.text)

        post_001_card = main_area.find('div', id='post-1')
        self.assertIn(self.post_001.title, post_001_card.text)
        self.assertIn(self.post_001.category.name, post_001_card.text)

        post_002_card = main_area.find('div', id='post-2')
        self.assertIn(self.post_002.title, post_002_card.text)
        self.assertIn(self.post_002.category.name, post_002_card.text)

        post_003_card = main_area.find('div', id='post-3')
        self.assertIn(self.post_003.title, post_003_card.text)
        self.assertIn('미분류', post_003_card.text)


        self.assertIn(self.post_001.author.username.upper(), main_area.text)
        self.assertIn(self.post_002.author.username.upper(), main_area.text)
        self.assertIn(self.post_003.author.username.upper(), main_area.text)

    def test_post_list_without_post(self):
        Post.objects.all().delete()
        self.assertEqual(Post.objects.count(), 0)

        response = self.client.get('/blog/')

        self.assertEqual(response.status_code, 200)

        soup = BeautifulSoup(response.content, 'html.parser')
        self.navbar_test(soup)
        self.assertIn('Blog', soup.title.text)

        # 2-2. 메인영역에 "아직 게시물이 없습니다." 라는 문구가 나온다.
        main_area = soup.find('div', id='main-area')
        self.assertIn('아직 게시물이 없습니다.', main_area.text)
    def test_post_detail(self):
        self.assertEqual(Post.objects.count(), 3)
        # 1.2 그 포스트의 url은 '/blog/1/' 이다.
        self.assertEqual(self.post_001.get_absolute_url(), '/blog/1/')

        #.2.   첫 번째 포스트의 상세 페이지 테스트
        # 2-1. 첫 번째 포스트의 url로 접근하면 정상적으로 작동한다. (status code : 200).
        response = self.client.get(self.post_001.get_absolute_url())
        self.assertEqual(response.status_code, 200)

        soup = BeautifulSoup(response.content, 'html.parser')

        # # 2-2. 포스트 목록 페이지와 똑같은 네비게이션 바가 있다.
        self.navbar_test(soup)

        # 2-3. 첫 번째 포스트의 제목이 웹 브라우저 탭 타이틀에 들어있다.
        self.assertIn(self.post_001.title, soup.title.text)

        # 2-4. 첫 번째 포스트의 제목이 포스트 영역에 있다.
        main_area = soup.find('div', id='main-area')
        post_area = main_area.find('div', id='post-area')
        self.assertIn(self.post_001.title, post_area.text)

        # # 2-5. 첫 번째 포스트의 작성자(author)가 포스트 영역에 있다. (아직 구현할 수 없음)
        self.assertIn(self.user_trump.username.upper(), post_area.text)
        # # 2-6. 첫 번째 포스트의 내용(content)이 포스트 영역에 있다.
        self.assertIn(self.post_001.content, post_area.text)

 

base.html

<!DOCTYPE html>
{% load static %}
<html>
<head>
    <title>{% block head_title %} Blog | 하도영 웹사이트 {% endblock %}</title>
    <link href="{% static 'blog/bootstrap/bootstrap.min.css' %}" rel="stylesheet" type="text/css">
    <!-- <link href="./practice.css" rel="stylesheet" type="text/css"> -->
    <!-- 주석처리 키 ctrl + /  -->
    <script src="https://kit.fontawesome.com/c1d4d1ab30.js" crossorigin="anonymous"></script>
</head>
<body>
{% include 'blog/navbar.html' %}
<div class="container">
    <!-- 블로그 리스트 페이지 만들기 강의 5:04 blog 글자 부분 container 클래스에 의해 do it django 와 같은 간격으로 맞춰짐 -->
    <!-- 이 아래는 9:3, 좁을때는 8:4 로 나눌거임 -->
    <div class="row my-3">
        <div class="col-md-8 col-lg-9", id="main-area">
            {% block main_area %}
            {% endblock %}
        </div>
        <div class="col-md-4 col-lg-3">
            <!-- Search widget-->
            <div class="card mb-4">
                <div class="card-header">Search</div>
                <div class="card-body">
                    <div class="input-group">
                        <input class="form-control" type="text" placeholder="Enter search term..." aria-label="Enter search term..." aria-describedby="button-search" />
                        <button class="btn btn-primary" id="button-search" type="button">Go!</button>
                    </div>
                </div>
                <!-- Categories widget-->
                <div class="card mb-4", id="categories-card">
                    <div class="card-header">Categories</div>
                    <div class="card-body">
                        <div class="row">
                            <ul>
                                {% for category in categories %}
                                <li>
                                    <a href="#!">{{ category.name }} ({{ category.post_set.count }})</a>
                                </li>
                                {% endfor %}
                                <!-- views.py 에 def get_context_data(self, **kwargs): 를 참고한다. -->
                                <li>
                                    <a href="#!">미분류 ({{ no_category_post.count }})</a>
                                </li>
                            </ul>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>


    {% include 'blog/footer.html' %}


    <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
            integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
            crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"
            integrity="sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct"
            crossorigin="anonymous"></script>
</body>

</html>

 

views.py

from django.shortcuts import render
from django.views.generic import ListView, DetailView
from .models import Post, Category

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

    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()
        # 미분류인 애들이 몇개인지 확인한다. filter기능을 이용해 none 인 애를 확인하고 count() 에 숫자를 담아 no_category_post.count에 넣어준다.
        return context
class PostDetail(DetailView):
    model = Post
    template_name = 'blog/post_detail.html'

# def index(request):
#     posts = Post.objects.all().order_by('-pk')
#     # pk는 순서대로 -pk  는 역순으로 최신 쓰레드가 위로 나오도록 조회
#     return render(
#         request,
#         'blog/index.html',
#         {
#             'posts': posts,
#         }
#     )

# def single_post_page(request, pk):
#     post = Post.objects.get(pk=pk)
#
#     return render(
#         request,
#         'blog/single_page.html',
#         {
#             'post': post,
#         }
#     )

 

post_list.html

{% extends 'blog/base.html' %}

{% block main_area %}

<h1> Blog </h1>
{% if post_list.exists %}

{% for p in post_list %}
<!-- Blog Post -->
<div class="card mb-4", id="post-{{ p.id }}">
    {% if p.head_image %}
    <img class="card-img-top" src="{{ p.head_image.url}}" alt="{{ p.title }}" />
    {% else %}
    <img class="card-img-top" src="https://picsum.photos/seed/{{ p.id }}/600/200" alt="{{ p.title }}" />
    {% endif %}
    <div class="card-body">
        <!--                                <div class="small text-muted">January 1, 2022</div>-->
        {% if p.category %}
        <span class="badge badge-secondary float-right">{{ p.category }} </span>
        {% else %}
        <span class="badge badge-secondary float-right">미분류</span>
        {% endif %}

        <h2 class="card-title h4">{{ p.title }}</h2>
        {% if p.hook_text %}
        <h5 class="text-muted">{{ p.hook_text }}</h5>
        {% endif %}

        <p class="card-text">{{ p.content | truncatewords:45 }}</p>
        <a href="{{ p.get_absolute_url }}" class="btn btn-primary">Read more →</a>
    </div>
    <div class="card-footer text-muted">
        Posted on {{ p.created_at }} by
        <a href="#">{{ p.author | upper }}</a>
    </div>
</div>
{% endfor %}
{% else %}
<h1> 아직 게시물이 없습니다. </h1>
{% endif %}

<!-- Pagination-->
<ul class="pagination justify-content-center my-4">
    <li class="page-item">
        <a class="page-link" href="#!">&larr; Older</a>
    </li>
    <li class="page-item disabled">
        <a class="page-link" href="#!">Newer &rarr;</a>
    </li>
</ul>
{% endblock %}

 

답변 1

1

몽상가님의 프로필 이미지
몽상가
질문자

자답으로 찾았습니다^^;

views.py 부분에서

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()

return context

 

context['no_category_post.count'] = Post.objects.filter(category=None).count()

 

.count로 입력해서 () 카운트를 부르지 못했었습니다.