Computer Science/BackEnd

장고 | 장고 공식 문서 내용 정리 #1-4 Getting started : writing your first Django app, part 3

토마토. 2022. 9. 3. 12:27
첫 장고 앱 만들기 #3
개요

Django는 views.py를 이용해서 기능을 제공하고 템플릿과 연결시켜준다. 

 

만약에 블로그 페이지를 만든다면 다음과 같은 views.py를 구성할 수 있다.

  • 블로그 메인 페이지 : 최신 몇 개의 포스팅을 보여주기
  • 카테고리별 세부 정보 페이지 : 하나의 카테고리에 대해 내용 보여주기
  • 연도 기반 페이지 : 한 연도에 발행된 모든 글을 보여주기
  • 월 기반 페이지 : 한 월에 발행된 모든 글을 보여주기
  • 날짜 기반 페이지 : 지정한 날짜에 발행된 모든 글을 보여주기
  • 댓글 작업 : 클릭한 포스팅에 대한 댓글을 게시하고 처리하기

 

지금 만드는 polls 페이지에는 다음 views.py를 만들어줄 수 있다. 

  • 질문 index 페이지 : 몇 개의 최신 질문을 표시하기
  • 질문 세부 정보 페이지 : 투표 양식이 있는 질문 텍스트 표시하기
  • 질문 결과 페이지 : 질문별 결과 표시
  • 투표 작업 : 투표를 처리하기

 

장고에서는 웹 페이지를 view를 통해 제공한다. 

views.py의 각 뷰는 파이썬 함수로 표현한다. 

 

장고의 URL 패턴은 일반적으로 /앱이름/<year>/<month>와 같은 형태를 가지고 있다. 

장고에서는 URL을 받아 view로 이동하기 위해 URLconfs를 사용한다. 

[참고] URL dispatcher | Django documentation | Django (djangoproject.com)

 

 

뷰 views 추가하기
from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.
def detail(request, question_id):
    return HttpResponse("You are looking at question %s" % question_id)

def results(request, question_id):
    response = "You are looking at the results of quesiton %s."
    return HttpResponse(response % question_id)

def vote(request, question_id):
    return HttpResponse("You are voting on question %s" % question_id)

간단한 view의 사례

django.http.HttpResponse를 이용해서 화면을 return해준다. 

근데 여기서 어떻게 200 OK, 404 어쩌구를 반환하는건지 잘 모르겠다. 

+ HttpResponse, JsonResponse, Response(rest-framework)의 차이도

 

from django.urls import path
from . import views

urlpatterns = [
    # /polls/
    path('', views.index, name='index'),
    # /polls/5
    path('<int:question_id>/', views.detail, name='detail'),
    # /polls/5/results/
    path('<int:question_id>/results/', views.results, name='results'),
    # /polls/5/vote/
    path('<int:question_id>/vote/', views.vote, name='vote'),
]

위와 같이 url과 view를 연결해주었다. 

 

사용자가 /polls/34를 요청

장고가 root_urlconf 설정에 따라 python module 불러옴

장고가 URL 패턴을 순회하면서 일치하는 것을 찾음 -> root에서 /polls/ 앱으로 이동

이제 polls.urls에서 다시 순회하면서 찾음

만약 일치한다면, mysite.urlsurlpattenrs'polls'"polls""34/"'<int:question_id/'detail()으로 반환

 

뷰에 기능 연결하기

view 함수들은 HttpResponse 객체를 반환하거나, Http404 같은 예외를 발생시킨다. 

 

index 함수에서 최신 5개의 설문조사를 표시하는 코드를 짜보자. 

from django.shortcuts import render
from django.http import HttpResponse
from .models import Question

# Create your views here.
def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    output = ', '.join([q.question_text for q in latest_question_list])
    return HttpResponse(output)

view 함수에서 페이지 디자인이 하드코딩되는 형식은 좋지 않다. 

장고에서는 템플릿 시스템을 사용해서 뷰에서 사용하는 템플릿을 만들어 python 코드와 디자인을 분리시킨다. 

일단 템플릿 디렉토리를 만들어주자. 

 

<!-- 만약 view 함수에 의해 latest_question_list 가 존재한다면 -->
{% if latest_question_list %}
<ul>
    {% for question in latest_question_list %}
        <li><a href="/polls/{{question.id}}/">{{question.question_text}}
        </a></li>
    {%endfor%}
</ul>
<!-- latest_question_list가 존재하지 않음-->
{% else %}
<p>No polls are available.</p>
<!-- if문 끝내기 -->
{% endif %}

탬플릿 태그를 이용해 로직을 표현해준다. 

 

이제 이 탬플릿 /templates/polls/index.html을 views.py의 index 함수에도 적용해준다. 

from django.shortcuts import render
from django.http import HttpResponse
from .models import Question
from django.template import loader

# Create your views here.
def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    template = loader.get_template('polls/index.html')
    context = {
        'latest_question_list' : latest_question_list,
    }
    return HttpResponse(template.render(context, request))

이때 사용되는 모듈은 django.template.loader, django.http.HttpResponse

 

<render()>

장고에서 템플릿을 로드하고, 데이터에 맞게 context를 채우고, HttpResponse 객체를 반환하는 것은 매우 빈번하게 사용되는 구문이다. 이를 편리하게 사용하기 위해 장고에서는 바로가기인 django.shortcuts 모듈을 제공한다. 

여기에서 render 함수를 사용하면, 간편하게 view 함수를 구성할 수 있다. 

 

render 인수

render(요청 객체(request), 템플릿 이름, 딕셔너리(선택 인수)

render 반환값 : HttpResponse 객체

from django.shortcuts import render
from django.http import HttpResponse
from .models import Question
from django.template import loader

# Create your views here.
def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    context = {
        'latest_question_list' : latest_question_list,
    }
    return render(request, 'polls/index.html', context)

 

404 에러
# Create your views here.
def detail(request, question_id):
    try:
        question = Question.objects.get(pk=question_id)
    except Question.DoesNotExist:
        raise Http404("Question does not exist")
    return render(request, 'polls/detail.html', {'question':question})

try except 구문으로 예외 처리를 해준다. 

만약 question object가 존재한다면, 이를 반환하여 내보내주고, 

만약 존재하지 않는다면 Http404 에러를 raise해주는 것이다. 

 

마지막 render에서 삽입한 템플릿 polls/detail.html은

{{ question }}

이렇게 간단하게 넣어주었다. 

 

<shortcut #2> get_object_or_404()

404는 매우 관용적인 문구이기 때문에, 

shortcut 모듈에서 get_object_or_404() 함수를 제공한다. 

get_object_or_404() 함수를 사용할 수 없는 경우 위와 같이 구현해주면 되겠다 ^^

 

# Create your views here.
def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/detail.html', {'question':question})

 

템플릿 시스템 사용하기
<h1>{{question.question_text}}</h1>
<ul>
    {%for choice in question.choice_set.all%}
        <li>{{choice.choice_text}}</li>
    {%endfor%}
</ul>

오홍

 

하드 코딩 URLs 삭제하기

기존 index.html 파일을 살펴보자. 

<!-- 만약 view 함수에 의해 latest_question_list 가 존재한다면 -->
{% if latest_question_list %}
<ul>
    {% for question in latest_question_list %}
        <li><a href="/polls/{{question.id}}/">{{question.question_text}}
        </a></li>
    {%endfor%}
</ul>
<!-- latest_question_list가 존재하지 않음-->
{% else %}
<p>No polls are available.</p>
<!-- if문 끝내기 -->
{% endif %}

 

앞서 path() 함수에서 세번째 인수로 name='어쩌구'로 정의해주었으므로, 

탬플릿 파일들에서 URL 경로를 하드코딩된 것을 name으로 바꿔줄 수 있다. 

 

<!-- 만약 view 함수에 의해 latest_question_list 가 존재한다면 -->
{% if latest_question_list %}
<ul>
    {% for question in latest_question_list %}
        <li><a href="{{%url 'detail' question.id %}}">{{question.question_text}}
        </a></li>
    {%endfor%}
</ul>
<!-- latest_question_list가 존재하지 않음-->
{% else %}
<p>No polls are available.</p>
<!-- if문 끝내기 -->
{% endif %}

이렇게 바꿔주었다! 

 

 

URL name을 사용하기

장고 프로젝트에는 하나의 프로젝트의 여러 개의 앱을 만들 수 있다. 

그래서 탬플릿 태그를 사용할 때 URL에 앱을 알아볼 수 있도록 해줄 수 있다. 

이때 app_name을 설정해준다. 

 

다시 urls.py 파일로 돌아가보자. 

from django.urls import path
from . import views

app_name = 'polls'

 

이것에 맞게 index.html 역시 수정해준다. 

<!-- 만약 view 함수에 의해 latest_question_list 가 존재한다면 -->
{% if latest_question_list %}
<ul>
    {% for question in latest_question_list %}
        <li><a href="{{%url 'polls:detail' question.id %}}">{{question.question_text}}
        </a></li>
    {%endfor%}
</ul>
<!-- latest_question_list가 존재하지 않음-->
{% else %}
<p>No polls are available.</p>
<!-- if문 끝내기 -->
{% endif %}