---
description: '210731'
---

# 템플릿 파일 모듈화 하기

## Extends - 화면 메인 영역 모듈화 하기

잠깐 이야기 할것이 있다. 많은 사람들이 오류가 나는 부분, AssertionError: 301 != 200 오류가 나는 사람들이 있을텐데. 강의에서 함수를 잘못 알려준 것 같다.

`models.py`

```python
def get_absolute_url(self):
    return f'/blog/{self.pk}'
    
def get_absolute_url(self):
    return f'/blog/{self.pk}/'
```

* 전자로 되어있으면 오류가 난다. 후자로 바꿔줄 것



post\_detail.html과 post\_list.html은 둘 다 동일한 navigation bar를 사용한다. 문제는, 이를 수정하려면 두번 수정해야 한다는 것. 만약 동일한 bar를 사용하는 html이 10개라면 10번 수정할 것인가?

아니다. 이럴 때는 따로 navigation bar를 관리하는 html을 만들 수 있다. 이를 base.html 이라고 하자

`base.html`

```markup
{% block main_area %}
    (id가 main_area인 태그 코드가 있던 곳)
{% endblock %}
```

기존에 코드를 모두 여기로 붙여넣고 id가 main\_area인 태그의 코드만 잘라낸 뒤 위와 같이 추가한다. 그리고 각각의 템플릿에 다음 코드를 추가하면 된다.

`post_detail.html` `post_list.html`

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

{% block main_area %}
    (id가 main_area인 태그 코드를 잘라내고 여기에 붙여넣는다)
{% endblock %}
```



두 템플릿의 네비게이션 바가 동일해진 모습

![](https://2275555537-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MNN4u9o9noCQwX8pO35%2F-Mg0wCdyB1GBhW_mHfcW%2F-Mg13gBWt8pSNnQ7A_Sp%2Fimage.png?alt=media\&token=f879916f-484d-4e93-8c6c-c446a83a0662)



이렇게되면, 네비게이션 바를 수정할 때 base.html만 수정하면 된다. 이것이 바로 모듈화 하는 이유.



또, 타이틀을 다음과 같이 작성해 줄 수 있다.

`base.html`

```markup
<head>
    <title>{% block head_title %}Blog | 상만두의 웹사이트{% endblock %}</title>
    <link href="{%  static 'blog/bootstrap/bootstrap.min.css' %}" rel="stylesheet" type="text/css">
    <script src="https://kit.fontawesome.com/726bbd6862.js" crossorigin="anonymous"></script>
</head>
```

이 코드 뜻은 `Blog | 상만두의 웹사이트` 라고 타이틀을 지정하되, head.title이 있다면 이 것으로 지정하라는 뜻이라고 한다. (나는 직관적으로 이해가 되지 않는 문법이다...)

그래서, post\_detail도 수정해주면 된다.

`post_detail.html`

```markup
{% block head_title %}
    {{ post.title }} | Blog
{% endblock %}
```





## Include - 네비게이션바, 푸터 모듈화 하기

일단 예전에 프론트단계에서 사용하던 html 코드를 그대로 가져왔기 때문에, 네비게이션바의 링크들이 제대로 연동이 되어있지 않다. 이를 연동시켜주기 위해 다음을 추가해준다

`tests.py`

```python
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/')
```

* post\_detail 이나 post\_list나 둘다 nav가 공통이므로 nav를 함수로 처리할 수 있도록 했다.
  * 따라서 soup를 인자로 받음
* 또, 링크를 연결해 주기 위해 `navbar.find`를 사용해서 실제 텍스트를 찾고 이 텍스트의 `href` 속성을 링크로 연결해준다.



또, footer나 navbar같은 것을 모듈화 할 필요가 있다. 이 때 `footer.htm`l과 `navbar.html`을 만든 뒤 해당 태그에 해당하는 코드를 각 파일에 잘라내어 붙여넣는다. 그 뒤, `base.html` 에는 다음과 같이 입력해주면 된다.

* 물론, 잘라낸 코드 위치에 해야 한다.

`base.html`

```markup
{% include 'blog/navbar.html' %}

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



정리하자면, extends과 include 둘 다 템플릿을 불러온다는 점에서 동일하지만 기본이 되는`base.html` 파일을 기준으로 extends는 자신을 여러 템플릿에서 쓸 수 있도록 바깥으로 보내는 방향이라면, include는 다른 템플릿을 자신의 코드에 붙여넣을 수 있또록 안으로 가져오는 방향이다.

* 그래서 extends의 경우에는 `post_detail.html` 과 `post_list.html` 이 `base.html` 을 불러와서 쓸 수 있었으며, include의 경우에는 `footer.html` 과 `navbar.html` 를 불러와서 `base.html` 에 쓸 수 있었다.

