본문으로 바로가기

홈페이지를 만들고 하위 메뉴를 만들 때, 맨 위 상단 네비게이션<nav>나 맨 아래의 <footer> 및 <head> 태그등 홈페이지 내 전체 HTML 파일에서 중복되는 부분들이 존재한다. 이에 대해 {% %}를 사용한 템플릿 확장기능을 통해 중복되는 부분을 제외하고 작성할 수 있다. 따라서 맨 처음 틀이 되는 base.html을 잘 만들어서 사용하는 것이 중요하다.

뿐만 아니라, html 파일 내에서 if, for 와 같은 구문을 사용할 수 있게 해준다.


1) 기본적으로 부모템플릿으로 쓸 base.html을 제작한다.

<base.html block 컨텐츠>

2) 부모템플릿을 상속 받아올 자식 템플릿을 생성한다.

<post_write.html block 컨텐츠>

 -  해당 html 문서에는
① {% extends 'base.html' %}
② {% block content %} - {% endblock %}
{% for in %} - {% endfor %}
④ {% ifequal %} - {% else %} - {% endifequal %}
⑤ {% if %} - {% endif %} 
⑥ {% csrf_token %}
 총 6가지 {% %}가 쓰였다. 

{% extends 'base.html' %}
    기본적으로 첫줄의 {% extends 'base.html' %}를 통해 해당 템플릿을 상속 받아온다.
    만약 post_write.html 파일에 {% extends 'base.html' %} 구문만 있다면, base.html과 똑같은 화면이 출력될 것이다.

{% block content %} - {% endblock %}
    {% block content %}는 {% endblock %}까지의 내용을 상속해주는 템플릿의 해당 위치에 상속받는 템플릿의
    해당 태그 안의 내용을 집어넣는 것이다.
   
    예시)

<base.html을 상속한 test.html 결과는 result.html 처럼 나온다.>

   위의 이미지처럼 base.html을 상속하여 test.html을 만들면, 해당 {% block content %}부터 {% endblock %}까지의
   내용이 그대로 들어가서 result.html 처럼 결과가 나오게 될 것이다. 

 {% for in %} - {% endfor %}
    {% for field in form %} 에서 field는 통상적으로 사용하는 for문의 i와 같은 변수 이름이라고 생각하면 된다.
    form은 Views.pypost_write(request): 함수에 있는 내용이다. 
    해당 함수는 forms.pyBoardForm()와 models.pyPost()를 받아와서 사용한다.
    순서상으로 HTML(Template) - views.py(View) - forms.py(Model) - models.py(Model)이 된다.

                     <models.py>                                                          <views.py>                                        <forms.py>   

   post_write 함수는 글쓰기 버튼을 눌렀을 때, 실행된다.

def post_write(request):
    if not request.user.is_authenticated:
        return redirect('/user/login/')
        # 로그인 여부를 확인하고, 로그인이 되어있지 않으면 로그인창으로 리다이렉트
    if request.method == 'POST':
        form = BoardForm(request.POST)
        # POST 방식의 request인 경우 form 객체를 생성
        if form.is_valid():
            user_id = request.user.id
            csuser = User.objects.get(pk=user_id)

            post = Post()
            # post 객체를 생성
            post.title = form.cleaned_data['title']
            post.content = form.cleaned_data['contents']
            # form의 title, contents 변수에 들어있는 내용을 post 객체로 가져옴
            post.author = csuser
            post.save()
            # 내용 저장

            return redirect('/board/post_list/')

    else:
        form = BoardForm()
    return render(request, 'board/post_write.html', {'form': form})

    위의 post_write 함수와 form, post의 변수들을 고려하여 html의 for문을 다시 보면 

 {% for field in form %}
        <div class="form-group">
            <label for="{{ field.id_for_label }}"> {{ field.label }} </label>
            {{ field.field.widget.name }}
            {% ifequal field.name 'contents' %}
            <textarea class="form-control" name="{{ field.name }}" ></textarea>
            {% else %}
            <input type="{{ field.field.widget.input_type }}" class="form-control" />
            {% endifequal %}
        </div>
        {% if field.error %}
        <span style="color:red">{{ field.errors }}</span>
        {% endif %}
        {% endfor %}

   form 안에서 for문을 돌리는데, div class 안에 {% ifequal %} 문에 따라 name이 contents일 때는 textarea class로,
   그렇지 않은 경우는 단순 class로 나누어서 출력하게 설정되어 있다. form의 변수를 가져와서 사용하므로 contents
   이고, 해당 페이지를 웹브라우저에서 보게되면, textarea로 설정되어 있는 것을 확인할 수 있다. form의 변수title
   contents 밖에 없으므로 두가지가 순서대로 나오고 끝난다.

<textarea class 확인>

④ {% ifequal %} - {% else %} - {% endifequal %}   

{% ifequal field.name 'contents' %}
<textarea class="form-control" name="{{ field.name }}" ></textarea>
{% else %}
<input type="{{ field.field.widget.input_type }}" class="form-control" />
{% endifequal %}

    가져온 field.name(form의 변수의 name)이 contents라면 textarea 클래스의 이름으로 넣고, contents가 아니라면
    그냥 일반 클래스를 사용한다. 게시판을 이루고 있는 여러 변수중 본문 내용(contents)부분만 textarea class로 설정
    하기 위하여 쓰였다. 다른 if 문들 처럼 if - else의 형태로 사용되었으며, 같거나 다른 경우만 판별하므로 ifequal이
    사용되었다. ifequal - else - endifequal의 형태로 사용된다.

 ⑤ {% if %} - {% endif %} 

{% if field.errors %}
<span style="color:red">{{ field.errors }}</span>
{% endif %}

   field.errors가 존재하면 해당 에러를 빨간 글씨의 span 태그요소로 나타내는 구문이다. 상단 html구문에서는 if
   field.error로 표현되었는데, error와 errors를 찾아본 결과 form에서 사용되는 것은 form.errors이다. (error X)
   ※ 참고 - https://docs.djangoproject.com/en/2.2/ref/forms/api/#django.forms.Form.errors

 

The Forms API | Django documentation | Django

Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate

docs.djangoproject.com

⑥ {% csrf_token %}
   CSRF_TOKEN 이라는 것을 만들어서 CSRF 공격을 방어하는 방법으로, 하단 링크를 참조바란다.

   ※ 참고 - https://docs.djangoproject.com/en/2.2/ref/csrf/

 

Cross Site Request Forgery protection | Django documentation | Django

Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate

docs.djangoproject.com

3) 따라서 어떤 홈페이지에서 변하지 말아야 하는 부분(nav, footer 등)을 기본 틀로 만들어 놓고, 페이지에 따라 내용이 바뀌는 부분을 body에 block content로 만들어 변경해줄 때 유용하게 사용할 수 있다. 위의 post_write.html에서는 base.html의 body에 들어갈 내용만 넣어주어, 실제 화면에서는 head, nav등은 base.html과 같고, body 태그 안의 내용만 해당 {% block content %}의 내용이 나타나게 된다. PPT의 슬라이드 마스터와 비슷한 개념으로 이해하면 쉽다.

기본적으로 상속받아 오는 ①의 기능과, 그 밖의 여러가지 기능들을 html에서 사용할 수 있는 것으로 생각하자.