리셋 되지 말자

[점프 투 장고] 조회와 템플릿 본문

Django

[점프 투 장고] 조회와 템플릿

kyeongjun-dev 2020. 12. 1. 16:37

목록조회

다음 페이지 요청시 등록한 질문들을 조회할 수 있도록 구현해 본다.

http://localhost:8000/pybo/

projects/mysite/pybo/views.py 수정

from django.shortcuts import render
from django.http import HttpResponse
from .models import Question
# Create your views here.
def index(request):
    """
    pybo 목록 출력
    """
    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')로 얻을 수 있다. order_by는 조회 결과를 정렬하는 함수이다. order_by('-create_date')의 의미는 작성일시 순인데 '-' 기호가 붙어 있으므로 작성일시의 역순으로 정렬하라는 의미이다.

render 함수는 조회된 질문목록 데이터를 pybo/question_list.html 파일에 적용하여 HTML로 변환해 주는 함수이다. 여기서 사용된 pybo/question_list.html 파일을 템플릿이라고 부른다. 템플릿 파일은 HTML파일과 비슷하지만 장고에서 사용하는 태그들을 사용할 수 있는 HTML 파일이다.

 

템플릿 데릭토리

render 함수에서 사용된 pybo/question_list.html 템플릿 파일을 작성해야 한다. 하지만 템플릿 파일을 작성하기 전에 템플릿 파일을 저장할 디렉토리를 먼저 만든다.

템플릿을 저장할 디렉토리는  config/settings.py 파일의 TEMPLETES 항목에 추가해준다.

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [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',
            ],
        },
    },
]

BASE_DIR아래에 'templates'로 지정한다. 이제 해당 경로에 맞게 templates 폴더를 생성한다.

장고는 DIRS에 설정한 디렉토리 외에도 앱(App) 디렉토리 하위에 있는 templates 디렉토리도 템플릿 디렉토리로 인식한다.

즉, pybo앱의 경우 다음의 디렉토리를 생성하면 별다른 설정없이 템플릿 디렉토리로 인식한다.

projects/mysite/pybo/templates

하지만 이 방법은 권장하지 않는다고 한다. 왜냐하면, 장고로 웹 사이트를 만들다 보면 앱(App)들이 계속 추가되는데 모든 앱의 템플릿을 전체적으로 관리할 수 있는 기준 템플릿 디렉토리를 사용하는 것이 관리에 용이하기 때문.

따라서 pybo 앱은 projects/mysite/pybo/templates 보다는 projects/mysite/templates/pybo 디렉토리를 사용하도록 한다. 그리고 공통으로 사용하는 템플릿은 projects/mysite/templates 에 저장한다.

 

템플릿 파일

render 함수에 사용된 템플릿 파일명은 다음과 같았다.

pybo/question_list.html

따라서 question_list.html 파일은 다음 경로에 위치하면 된다.

{% if question_list %}
    <ul>
    {% for question in question_list %}
        <li><a href="/pybo/{{ question.id }}/">{{ question.subject }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>질문이 없습니다.</p>
{% endif %}

{% %} 를 템플릿 태그라고 한다.

{% if question_list %}는 다음처럼 해석된다.

question_list 가 있다면 (※ question_list는 render함수로 전달받은 "질문목록"에 해당되는 데이터이다.)

{% for question in question_list %}는 다음처럼 해석된다.

question_list 를 반복하며 순차적으로 하나씩 question에 대입

{{ question.id }} 는 다음처럼 해석된다.

for문에 의해 대입된 question 객체의 id번호를 출력

{{ question.subject }} 는 다음처럼 해석된다.

for문에 의해 대입된 question 객체의 제목을 출력

 

템플릿 태그

장고에서 사용되는 템플릿 태그는 사실 다음 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 객체를 사용할 수 있다.

forloop 속성설명

forloop.counter 루프내의 순서로 1부터 표시
forloop.counter0 루프내의 순서로 0부터 표시
forloop.first 루프의 첫번째 순서인 경우 True
forloop.last 루프의 마지막 순서인 경우 True

3. 객체 출력

객체를 출력하기 위한 태그의 사용법은 다음과 같다.

{{ 객체 }}

예) {{ item }}

객체에 속성이 있는 경우는 파이썬과 동일한 방법으로 도트(.) 문자를 이용하여 표시하면 된다.

{{ 객체.속성 }}

예) {{question.id}}, {{question.subject}}

이 책에서는 파이보에 필요한 템플릿 문법이 나올 때마다 자세하게 알아볼 것이다. 만약 지금 당장 어떤것들이 있는지 자세히 알고 싶다면 다음 URL을 참조하도록 하자.
https://docs.djangoproject.com/en/3.0/topics/templates/

 

테스트

여기까지 수정 후, pybo 페이지로 접속하면 변경된 화면을 확인할 수 있다. (템플릿 디렉토리 추가후에 로컬서버를 재 시작해주어야 한다.

상세조회

question 링크를 클릭하면 다음과 같이 404오류가 표시된다. 이때 url을 보면 /pybo/1/로 요청하는 것을 확인할 수 있다. 이 숫자는 question의 id 이다. 이에 대한 페이지에 대해 URL매핑이 정의되어 있지 않아서 오류가 출력된다.

 

urls.py

http://localhost:8000/pybo/2/

위의 URL의 의도는 'Question 모델 데이터 중 2라는 id값을 가지고 있는 데이터를 조회' 한다는 것이다.

이를 위해서 pybo/urls.py를 수정한다.

from django.urls import path

from . import views

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

path('<int:question_id>/', views.detail) 매핑으로 인해 /pybo/2/ 와 같은 페이지가 요청되면, /pybo/<int:question_id>/가 적용되어 question_id에 2라는 값이 저장되고 views.detail 함수가 실행된다. (여기서 int는 숫자값이 매핑됨을 의미한다.)

 

views.py

이제 pybo/views.py에 detail 함수를 추가한다.

from django.shortcuts import render
from django.http import HttpResponse
from .models import Question
# Create your views here.
def index(request):
    """
    pybo 목록 출력
    """
    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):
    """
    pybo 내용 출력
    """
    question = Question.objects.get(id=question_id)
    context = {'question': question}
    return render(request, 'pybo/question_detail.html', context)

index함수와 비교해서 매개변수가 하나 추가되었다. localhost:8000/pybo/2/가 요청되면, 매개변수인 qeustion_id에 2라는 값이 전달된다.

 

question_detail.html

상세조회 화면에 해당되는 pybo/question_detail.html 템플릿을 다음과 같이 작성한다.

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

그리고 다시 접속한다.

 

오류페이지

localhost:8000/pybo/20과 같이 존재하지 않는 question에 접속하면 다음과 같이 오류가 발생한다.

전달된 question_id가 30이라서 Question.objects.get(id=30)이 호출되어 해당 질문을 찾을 수 없다는 오류다.

현재 config/settings.py 파일에 DEBUG=True로 설정되어 있어서 위와 같은 오류가 표시되지만, 실제 운영환경은 DEBUG=False로 설정되기 때문에 "Server Error (500)"가 발생하게 된다고 한다.

이렇게 잘못된 URL이 요청될 경우 "Server Error (500)" 오류를 리턴하는 것은 바람직하지 않다. 보통 이런 경우에는 "Not Found (404)"오류를 리턴해야 한다.

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

위처럼 존재하지 않는 데이터를 요청할 경우 500 오류페이지 대신 404 오류페이지를 출력하도록 detail 함수를 수정한다.

from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse
from .models import Question
# Create your views here.
def index(request):
    """
    pybo 목록 출력
    """
    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):
    """
    pybo 내용 출력
    """
    # question = Question.objects.get(id=question_id)
    question = get_object_or_404(Question, pk=question_id)
    context = {'question': question}
    return render(request, 'pybo/question_detail.html', context)

get_object_or_404 함수는 django.shortcuts 패키지에서 import하여 사용한다. 여기서 사용된 pk는 Question모델의 기본키(Primary Key)인 id를 의미한다.

다시 접속해 보면, 404 페이지가 출력되는 것을 확인할 수 있다.

'Django' 카테고리의 다른 글

[점프 투 장고] 데이터 저장  (0) 2020.12.01
[점프 투 장고] URL과 네임스페이스  (0) 2020.12.01
[점프 투 장고] 장고 관리자  (0) 2020.12.01
[점프 투 장고] model  (0) 2020.12.01
[점프 투 장고] url과 view  (0) 2020.12.01
Comments