1. 질문 목록
: 등록한 질문들을 게시물 목록으로 조회하는 기능
// mysite/projects/pybo/views.py
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') 로 얻을 수 있다.
- order_by : 정렬하는 함수이다. order_by('-create_date')는 작성일시 역순으로 정렬하라는 의미이다.
- - 기호가 붙어 있으면 역방향, 없으면 순방향 정렬을 의미한다. 게시물은 보통 최신순으로 보기 때문에 작성일시의 역순으로 정렬했다.
- context : question_list를 html파일에서 쓸 수 있도록 넘겨준다. {a:a}형식으로 넘겨주어 사용한다.
- render : 파이썬 데이터를 템플릿에 적용하여 HTML로 반환하는 함수이다. 즉, 위에서 사용한 render 함수는 질문 목록으로 조회한 question_list 데이터를 pybo/question_list.html 파일에 적용하여 HTML을 생성한후 리턴한다.
- 여기서 사용된 pybo/question_list.html과 같은 파일을 템플릿(Template)이라고 부른다. 템플릿 파일은 HTML 파일과 비슷하지만 파이썬 데이터를 읽어서 사용할수 있는 HTML 파일이다.
1) 템플릿 디렉터리
// mysite/projects/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',
],
},
},
]
settings.py에 들어가서 TEMPLATES> DIRS부분을 수정한다. 템플릿 파일을 저장할 디렉터리를 만들어야 위에서 작성한 render함수의 템플릿 파일을 적용할 수 있다.
- DIRS :템플릿 디렉터리를 여러개 등록할 수 있도록 리스트로 되어 있다.
2) 템플릿 폴더 생성하기
mkdir templates
장고는 DIRS에 설정한 디렉터리 외에도 앱 디렉터리 바로 하위에 있는 templates 디렉터리도 템플릿 디렉터리로 인식한다. 즉, pybo 앱의 경우 다음의 디렉터리를 생성하면 별다른 설정없이 템플릿 디렉터리로 인식한다.
mysite/projects/pybo/templates
하나의 웹 사이트에서 여러 앱을 사용할 때 여러 앱의 화면을 구성하는 템플릿은 한 디렉터리에 모아 관리하는 편이 여러모로 좋기 때문에 앱(App) 디렉터리 하위에 템플릿 디렉터리를 두는 방법을 권장하지 않는다.
3) 템플릿 파일 생성하기
템플릿 파일 생성하면 위와 같은 구조를 가지고 있다.
// 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 %}
{% 와 %} 로 둘러싸인 문장들을 볼 수 있는데 이러한 것들을 템플릿 태그라고 한다.
템플릿 디렉터리 추가후에는 로컬 서버를 재시작하고, 페이지를 새로고침하면 아래와 같은 화면을 볼 수 있다.
2. 질문 상세
: 게시물 목록 중 한 건의 데이터를 상세하게 조회하는 기능
질문 목록 중 한 개를 선택하여 클릭해 보면 위와 같은 화면을 볼 수 있다. 이 오류를 고치기 위해서 url을 맵핑해주어야 한다.
1) urls.py
// 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) 라는 URL 매핑을 추가했다. 여기에 등록한 매핑 룰에 의해 http://localhost:8000/pybo/<int:question_id>/ 가 적용되어 question_id 에 3이 저장되고 views.detail 함수도 실행된다. <int:question_id> 에서 int는 숫자가 매핑됨을 의미한다.
2) views.py
// 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)
detail 함수 호출시 전달되는 매개변수가 request 외에 question_id가 추가되었다. 매개변수 question_id에는 URL 매핑시 저장된 question_id가 전달된다.
즉, http://localhost:8000/pybo/3/ 페이지가 요청되면 매개변수 question_id에 3이 세팅되어 detail 함수가 실행된다.
3) question_detail.html
templates/pybo폴더에 question_detail.html을 생성한다.
// pybo/question_detail.html
<h1>{{ question.subject }}</h1>
<div>
{{ question.content }}
</div>
{{ question.subject }}과 {{ question.content }}의 question은 detail 함수에서 템플릿에 context 변수로 전달한 Question 모델 객체이다.
3. 오류 페이지
http://localhost:8000/pybo/30/ 페이지를 요청해보면 아래와 같이 나온다.
DoesNotExist 오류가 발생한다. 이 오류는 전달된 question_id가 30이기 때문에 Question.object.get(id=30)이 호출되어 발생한 오류이다. 이 때 브라우저에 전달되는 오류코드는 500이다.
이렇게 없는 데이터를 요청할 경우 500 오류 페이지 보다는 "Not Found (404)" 페이지를 리턴하는 것이 바람직하다.
// pybo\\views.py
from django.shortcutsimport render, get_object_or_404from .modelsimport Question
(... 생략 ...)
defdetail(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)에 해당하는 값을 의미한다.
이렇게 수정하고 다시 http://localhost:8000/pybo/30/ 페이지를 요청해 보자. 이번에는 500 대신 404 오류 페이지가 출력되는 것을 확인할 수 있다.