Web/Django

Django - 조회와 템플릿

괘창 2024. 5. 16. 22:43

● 조회와 템플릿

- 질문 목록 : 등록한 질문들을 게시물 목록으로 조회하는 기능
- 질문 상세 : 게시물 목록 중 한 건의 데이터를 상세하게 조회하는 기능

 

- 질문 목록

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 오류 페이지 출력