[Python] django 장고 템플릿
본문 바로가기

[Python] django 장고 템플릿

액트 2022. 8. 31.

이제는 요청과 응답을 저장해 둔 데이터를 조회하여 웹 브라우저에 출력하고자 합니다.

데이터를 DB에서 조회하고 불러와서 웹 브라우저에 HTML 코드로 변환하여 출력해야 합니다.

하지만, 파이썬 코드는 브라우저에서 동작하지 않습니다. 브라우저는 알다시피 HTML 코드만 동작합니다.

장고에 내장된 템플릿 태그(template tags)는 파이썬 코드를 HTML로 바꿔주어, 빠르고 쉽게 동적인 웹 사이트를 만들 수 있게 도와줍니다.

 

그럼 앞전에 작성해 둔 질문들을 DB에서 조회하여 웹브라우저 출력될 수 있도록 구현해 봅시다. 

먼저, 템플릿을 보관할 디렉토리를 생성해 주어야 합니다.

 

1. 템플릿 생성

mysite\ 아래에 templates 디렉토리를 생성합니다.

해당 프로젝트가 이 템블릿 디렉토리의 저장경로를 알 수 있게 config/settings.py 파일의 TEMPLATES 항목에 설정합니다.

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],			#수정
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

DIRS 부분에 []을 [os.path.join(BASE_DIR, 'templates')] 라고 수정합니다. 

DIRS는 템플릿 디렉터리를 여러 개 등록할 수 있도록 리스트로 되어 있습니다. BASE_DIR은 c:\projects\mysite 입니다. setting.py 파일 윗부분에 정의되어 있습니다.

추가로 pybo 앱에서 사용할 템플릿을 mysite/templates 디렉터리 아래에 pybo 이름으로 생성합니다.

그리고 실제로 사용하는 템플릿 파일을 만들어야 합니다.

파일명은 question_list.html 입니다. 경로는 mysite\templates\pybo 입니다.

templates\pybo 디렉터리에서 마우스 우클릭 > New > HTML File 클릭합니다. 

이름을 question_list.html 로 작성합니다.,

그리고 pybo/question_list.html 파일을 기존에 작성되어 있는 거는 다 삭제하시고 다음과 같이 작성하고 저장합니다.

{% if question_list %}	#question_list가 있다면
    <ul>
    {% for question in question_list %}		#question_list를 순회하며 순차적으로 하나씩 question에 대입
        <li><a href="/pybo/{{ question.id }}/">{{ question.subject }}</a></li>	#id와 제목을 출력
    {% endfor %}
    </ul>
{% else %}
    <p>질문이 없습니다.</p>
{% endif %}

{%와 %}로 둘러싸인 문장을 템플릿 태그라고 합니다. 

 

템플릿 태그

장고에서 사용하는 템플릿 태그는 다음 3가지 유형만 알면 됩니다.

1) 분기

분기문 태그의 사용법은 다음과 같습니다.

{% if 조건문1 %}
    <p>조건문1에 해당되는 경우</p>
{% elif 조건문2 %}
    <p>조건문2에 해당되는 경우</p>
{% else %}
    <p>조건문1, 2에 모두 해당되지 않는 경우</p>
{% endif %}

파이썬의 if문과 다를바가 없습니다. 다만 항상 {% endif %} 태그로 닫아주어야 합니다.

2) 반복

반복문 태그 사용법은 다음과 같습니다.

{% for item in list %}
    <p>순서: {{ forloop.counter }} </p>
    <p>{{ item }}</p>
{% endfor %}

파이썬의 for문과 비슷합니다. 역시 항상 {% endfor %} 태그로 닫아주어야 합니다. 그리고 템플릿 for문 안에서는 다음과 같은 forloop 객체를 사용할 수 있습니다.

3) 객체 출력

객체를 출력하이 위한 태그의 사용법입니다.

{{ 객체.속성 }}

예)

{{question.id}}, {{question.subject}}

 

2. 뷰 파일 수정

DB에 저장되어 있는 데이터가 출력될 수 있도록 이번엔 pybo/views.py 파일의 index함수를 다음과 같이 수정합니다.

from django.shortcuts import render
from .models import Question

def index(request):
    question_list = Question.objects.order_by('-create_date')
    context = {'question_list': question_list}
    return render(request, 'pybo/question_list.html', context)

질문 목록 데이터는 Question.objects.order_by('-create_date')로 조회 후 question_list 변수에 대입합니다.

order_By는 조회 결과 값을 정렬하는 함수입니다.

-create date는 작성일시를 역순으로 정렬하라는 뜻입니다. 대소문자를 구분하니 소문자로 작성해 주셔야 합니다.

- 기호가 붙어 있으면 역방향, 없으면 순방향 정렬을 의미합니다. 

render 함수는 파이썬 데이터를 템플릿에 적용하여 HTML로 반환하는 함수입니다.

즉, 위에서 사용한 render 함수는 질문 목록으로 조회한 question_list 데이터를 pybo/question_list.html 파일에 적용하여 HTML을 생성한 후 리턴합니다.

setting.py 파일을 수정한 것이기 때문에 적용을 위해서는 서버를 재시작해줘야 합니다.

서버 재시작한 후에 http://localhost:8000/pybo 에 접속하면 아래와 같이 출력되는 것을 확인할 수 있습니다.

해당 질문을 클릭하면 아래와 같이 id 같이 하위 페이지로 열리는 것을 확인하실 수 있습니다.

위와 같이 오류가 표시된 이유는 http://localhost:8000/pybo/2 와 같은 페이지에 대한 URL 매핑이 없기 때문입니다.

 

3. URL 매핑

URL 매핑을 위해서 mysite/pybo/urls.py 파일을 수정합니다.

path('', views.index), 아래에 path('<int:question_id>/', views.detail), 를 추가합니다.

from django.urls import path
from . import views

urlpatterns = [
    path('', views.index), 
    path('<int:question_id>/', views.detail),     # << 추가
]

http://localhost:8000/pybo/2/ 페이지가 요청되면 여기에 등록된 매핑 룰에 의해

http://localhost:8000/pybo/<int:question_id>/가 적용되어 question_id에 2가 저장되고 views.detail 함수가 실행됩니다.

이제 views.detail 함수를 정의해 줍니다.

mystie/pybo/views.py 파일로 이동합니다

아래와 같이 detail 함수를 정의합니다.

def detail(request, question_id):
    question = Question.objects.get(id=question_id)
    context = {'question':question}
    return render(request, 'pybo/question_detail.html', context)

question_id 매개변수에 따라 화면을 출력해줍니다.

http://localhost:8000/pybo/2/ 페이지가 요청되면 매개변수 question_id에 2가 세팅되어 detail 함수가 출력됩니다.

 

4. 템플릿 파일 수정

이제 http://localhost:8000/pybo/2/ 페이지에 사용될 html 파일을 만들어 주어야 합니다.

템플릿 파일을 만드는 것이므로 경로는 mysite/templates/pybo 이고 파일의 이름은 question_detail.html 으로 합니다.

내용은 아래와 같이 작성하겠습니다.

<h1>{{ question.subject }}</h1>
<div>
    {{ question.content }}
</div>

 

저장 후 http://localhost:8000:/pybo/2/ 페이지를 다시 요청하면 아래와 같이 정상 출력될 것입니다.

5. URL 매핑이 없을 경우의 오류 페이지

예를 들어, http://localhost:8000/pybo/30/ 페이지를 요청할 경우 아래와 같이 오류가 발생합니다.

이 오류는 question_id 값이 30이기 때문에 Qustion.odject.get(id=30) 이 호출되어 발생한 오류 입니다.

이때 브라우저에 전달되는 오류 코드는 500입니다.

이렇게 없는 데이터를 요청할 경우 500 오류 페이지 보다는 "Not Found (404)" 페이지를 리턴하는 것이 웹 개발에 바람직합니다.

[ HTTP 주요 응답코드의 종류 ]

오류코드 설명
200 성공 (OK)
500 서버오류 (Internal Server Error)
404 서버가 요청한 페이지(Resource)를 찾을 수 없음 (Not Found)

위와 같이 없는 페이지를 요청할 경우 500 페이지 대신 404 페이지를 출력하도록 deatil 함수를 다음과 같이 수정합니다.

상단에 get_object_or_404 를 추가합니다.

from django.shortcuts import render, get_object_or_404

그리고 detail 함수에 아래와 같이 수정합니다.

def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    context = {'question': question}
    return render(request, 'pybo/question_detail.html', context)

Question.object.get(id=question_id)를 get_object_or_404(Question, pk=question_id)로 바꾸었습니다. 

이렇게 수정하고 없는 페이지를 다시 한번 요청하면 500대신 404가 리턴되어 404 오류 페이지를 출력합니다.

 

정리


정리하자면, 템플릿 파일이란 확장자가 html인 파일이고 

템플릿 파일의 역할은 파이썬의 코드를 웹 브라우저가 해석할 수 있게 변경해주는 역할입니다.

http://localhost:8000/pybo 페이지의 템플릿 파일은 question_list.html 입니다.

http://localhost:800/pybo/ 요청이 오면 제일 먼저 mysite/pybo/urls.py 을 참고합니다. 

urlpatterns = [
    path('', views.index),
    path('<int:question_id>/', views.detail),
]

위와 같이 http://localhost:8000/pybo/ 페이지를 요청하면 views.py의 index 함수를, 

http://localhost:8000/pybo/id/ 페이지를 요청하면 views.py의 detail 함수를 호출합니다.

자 그럼 이제 views.py 파일을 확인합니다.

def index(request):
    question_list = Question.objects.order_by('-create_date')
    context = {'question_list': question_list}
    return render(request, 'pybo/question_list.html', context)


def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    context = {'question': question}
    return render(request, 'pybo/question_detail.html', context)

위와 같이 정의되어 있습니다.

index 함수의 리턴값은 question_list.html을 HTMl 로 변환한 값입니다.

(render 함수는 파이썬 데이터를 템플릿에 적용하여 HTML로 반환하는 함수입니다.)

이렇게 하여 화면에 출력되는 것입니다.

http://localhost:8000/pybo 호출 -> urls.py -> views.py

 

 

점프 투 장고, 장고걸스 등을 바탕으로 공부한 내용을 정리한 글입니다. 더 자세한 사항은 책을 참고 부탁드립니다.

댓글