템플릿 모듈화 하기

Posted on 2021-08-25 by GKSRUDTN99
Django로 웹사이트 만들기 장고

템플릿 모듈화가 필요한 이유

하나의 웹 페이지 내에서 네비게이션 바와 푸터는 같은 디자인을 가지고 있다.

그래서 네비게이션 바와 푸터는 모두 동일하게 사용하고, main 영역만 매번 채우도록 디자인 하는 것이 좋다.

템플릿 모듈화 하는 방법

1. post_list.html 을 복사하여 base.html을 만든다.

2. base.html 에서 main-area라는 id를 가진 div 안의 내용을 모두 삭제한다.

3. {% block [block 이름] %}{% endblock %}을 이용해 block을 만든다.

# base.html

<div class="col-md-8 col-lg-9" id="main-area">
            {% block main_area %}
            {% endblock %}
        </div>

4. post_list.html에서 main-area을 제외한 부분들을 모두 삭제한다.

5. post_list.html의 첫 부분에 {% extends 'blog/base.html' %}을 추가한다.

6. {% block [block 이름] %}{% endblock %}을 이용해 block에 들어갈 내용을 작성한다.

# blog_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">
                <a href="#!">
                    {% if p.head_image %}
                        <img class="card-img-top" src="{{ p.head_image.url }}"
                             alt="{{ p }}"/>
                    {% else %}
                        <img class="card-img-top" src="https://picsum.photos/seed/{{ p.id }}/800/200"
                             alt="random_image">
                    {% endif %}
                </a>
                <div class="card-body">
                    <div class="small text-muted">
                        Posted on {{ p.created_at }} by
                        <a href="#">작성자명 쓸 위치(개발 예정)</a>
                    </div>
                    <h2 class="card-title">{{ 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 class="btn btn-primary" href="{{ p.get_absolute_url }}">Read more →</a>
                </div>
            </div>
        {% endfor %}
    {% else %}
        <h3>아직 게시물이 없습니다.</h3>
    {% endif %}
    <!-- Pagination-->
    <nav aria-label="Pagination">
        <hr class="my-0"/>
        <ul class="pagination justify-content-center my-4">
            <li class="page-item disabled"><a class="page-link" href="#" tabindex="-1" aria-disabled="true">Newer</a>
            </li>
            <li class="page-item active" aria-current="page"><a class="page-link" href="#!">1</a></li>
            <li class="page-item"><a class="page-link" href="#!">2</a></li>
            <li class="page-item"><a class="page-link" href="#!">3</a></li>
            <li class="page-item disabled"><a class="page-link" href="#!">...</a></li>
            <li class="page-item"><a class="page-link" href="#!">15</a></li>
            <li class="page-item"><a class="page-link" href="#!">Older</a></li>
        </ul>
    </nav>
{% endblock %}

python manage.py test를 통해 테스트 해본다.

✔︎ 위의 테스트는 post_detail test도 포함하므로 fail된다.
✔︎ python manage.py test blog.tests.TestView.test_post_list를 통해 테스트한다.

blog_detail에도 모듈 적용하기

blog_detail에서 <div class="col-lg-8">안에 있는 내용들을 모두 main_area block안에 넣고, 나머지는 모두 삭제하면 적용된다.

하지만, test를 수행해보면 title에 포스트의 제목이 표시되지 않는 것을 확인할 수 있다.

이를 위해, base.html을 다음과 같이 수정한다.

# blog/base.html
<head>
    <meta charset="UTF-8">
    <title>{% block head_title %}Blog{% endblock %}</title>
    <link href="{% static 'blog/bootstrap/bootstrap.min.css' %}" rel="stylesheet" media="screen">
    <script src="https://kit.fontawesome.com/1205323533.js" crossorigin="anonymous"></script>

</head>

위의 구조는 head_title block을 따로 정의하면 그 내용을 block에 넣고, 따로 정의 되지 않았다면 Blog를 title로 표시하는 코드이다.

post_detail.html에서만 head_title block을 정의해준다.

# blog/post_detail.html
{% block head_title %}
    {{ post.title }} - Blog
{% endblock %}

네비게이션 바 테스트 코드 수정하기

현재 네비게이션 바의 테스트 코드는 'Blog'과 'About Me'의 포함 여부만 검사하고 있다.

네비게이션 바의 링크가 올바를 url로 안내하는지 확인하는 테스트 코드를 작성한다.

네비게이션 테스트 함수 정의

TestCase안에 navbar_test라는 함수를 새로 정의한다.

함수 이름이 test로 시작하면 새로운 test로 인식하므로 주의한다.

# blog/tests.py

class TestView(TestCase):
    def setUp(self):
        self.client = Client()

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

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

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

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

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

...

네비게이션 바를 navbar.html로 모듈화하기

1. navbar.html을 새로 만들고, 네비게이션 바에 해당하는 코드를 붙여 넣는다.

2. base.html에 네비게이션 코드가 있던 부분에 {% include 'blog/navbar.html' %} 를 입력하면, navbar.html의 내용이 그대로 base.html에 들어간다.