Django - 조회와 템플릿
● 조회와 템플릿
- 질문 목록 : 등록한 질문들을 게시물 목록으로 조회하는 기능
- 질문 상세 : 게시물 목록 중 한 건의 데이터를 상세하게 조회하는 기능
- 질문 목록
http://localhost:8000/pybo/
[파일명: projects/mysite/pybo/views.py]
from django.http import HttpResponse # 삭제
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)
** order_by('-create_date') 작성일시 역순으로 정렬하라는 의미로 - 기호가 있으면 역방향/없으면 순방향 정렬 의미
** pybo/question_list.html의 html을 템플릿(Template)이라 한다.
** 템플릿은 HTML 파일과 비슷하지만, 파이썬 데이터를 읽어 사용할 수 있는 HTML
※ render() 함수
내가 가진 templates에 data를 넣어 보내고 싶을 때 이용
render(request, template_name, context=None, content_type=None, status=None, using=None)
** request와 template_name 작성 필수
- 템플릿 디렉토리
render 함수에서 사용한 pybo/question_list.html 템플릿 파일 작성 필요
템플릿을 저장할 디렉토리는 config/settings.py 파일의 TEMPLATES 항목에 설정 필요
[파일명: projects/mysite/config/settings.py]
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',
],
},
},
]
** DIRS는 템플릿 디렉토리를 여러개 등록할 수 있도록 리스트로 되어 있다
** c:\projects\mysite\templates >> 추가한 디렉토리의 전체 경로
※ 상기 주소의 디렉토리는 현재 없기 때문에 (mysite) c:\projects\mysite> mkdir templates 생성 필요

■ 모든 앱이 공통으로 사용할 템플릿 디렉터리 - projects/mysite/templates
■ pybo 앱이 사용할 템플릿 디렉터리 - projects/mysite/templates/pybo
■ common 앱이 사용할 템플릿 디렉터리 - projects/mysite/templates/common
- 템플릿 파일
render 함수에서 사용한 템플릿 파일명은 pybo/question_list.html로 다음과 같은 경로에 파일 생성이 필요하다.
[파일명: projects/mysite/templates/pybo/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 %}
※ question_list.html에 사용된 템플릿 태그
| 태그 | 설명 |
| {% if question_list %} | question_list가 있다면 |
| {% for question in question_list %} | question_list를 순회하며 순차적으로 하나씩 question에 대입 |
| {{ question.id }} | for문에 의해 대입된 question 객체의 id 번호를 출력 |
| {{ question.subject }} | for문에 의해 대입된 question 객체의 제목을 출력 |
- 템플릿 태그
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/4.0/topics/templates/
● 질문 상세
- url.py
[파일명: projects/mysite/pybo/urls.py]
from django.urls import path
from . import views
urlpatterns = [
path('', views.index),
path('<int:question_id>/', views.detail), #<int:question_id>숫자 매핑
]
** path('<int:question_id>/', views.detail) URL 매핑 추가
http://localhost:8000/pybo/3/ 페이지가 요청되면 url.py에 등록한 매핑 룰에 의해 http://localhost:8000/pybo/<int:question_id>/ 가 적용되어 question_id 에 3이 저장되며 views.detail 함수 실행
- views.py
detail 함수 추가
[파일명: projects/mysite/pybo/views.py]
(... 생략 ...)
def detail(request, question_id):
question = Question.objects.get(id=question_id)
context = {'question': question}
return render(request, 'pybo/question_detail.html', context)
** index 함수와 크게 다른 부분은 없다.
다만 detail 함수 호출시 전달되는 매개변수가 request 외에 question_id가 추가되었다.
매개변수 question_id에는 URL 매핑시 저장된 question_id가 전달된다.
즉, http://localhost:8000/pybo/3/ 페이지가 요청되면 매개변수 question_id에 3가 세팅되어 detail 함수가 실행된다.
- question_detail.html
[파일명: projects/mysite/templates/pybo/question_detail.html]
<h1>{{ question.subject }}</h1>
<div>
{{ question.content }}
</div>
** {{ question.subject }}과 {{ question.content }}의 question은
detail 함수에서 템플릿에 context 변수로 전달한 Question 모델 객체이다.

** http://127.0.0.1:8000/pybo/4/ 페이지 요청 시 질문 상세 정상 출력
- 오류페이지
http://localhost:8000/pybo/30/ 요청

** Question.object.get(id=30)이 호출되어 발생한 오류 // 데이터가 없는 내용 호출 시 오류가 발생한다
[HTTP 주요 응답 코드 종류]
| 오류코드 | 설명 |
| 200 | 성공 (OK) |
| 500 | 서버오류 (Internal Server Error ) |
| 404 | 서버가 요청한 페이지(Resource)를 찾을 수 없음 (Not Found) |
없는 데이터를 요청할 경우 404 페이지 출력하는 방법
[파일명: projects\mysite\pybo\views.py]
from django.shortcuts import render, get_object_or_404
from .models import Question
(... 생략 ...)
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.objects.get(id=question_id) 를 get_object_or_404(Question, pk=question_id)로 수정
** pk는 Question 모델의 기본키(Primary Key)에 해당하는 값을 의미

** Question.object.get(id=30) 입력 시 404 오류 페이지 출력