본문 바로가기
카테고리 없음

파이썬 - 장고 - 투표하기 공식 튜토리얼 따라하기 #3

지난 게시글에 이은 장고 공식 튜토리얼 투표하기 따라하기 3편입니다 :)


역시 크레이 입맛(?)에 맞게 일부 가감한 부분이 있습니다.

지난 게시글 : https://itadventure.tistory.com/665

 

파이썬 - 장고 - 투표하기 공식 튜토리얼 따라하기 #2

지난 게시글에 이은 장고 공식 튜토리얼 투표하기에 대한 따라하기의 다음 편입니다 :)한국 상황에 맞게 일부 수정한 부분, 그 외 크레이가 나름대로 일부 가감한 부분이 있습니다.https://itadventur

itadventure.tistory.com

https://docs.djangoproject.com/en/5.0/intro/tutorial03/


상세 페이지 URL 만들기

지금까지는 첫페이지 주소만 만들었습니다.
http://127.0.0.1:8000/polls/ URL 주소가 바로 그것인데요.
이제 실제 데이터를 표시하는 페이지를 만들어 볼 차례입니다.
장고의 URL 주소는
요새 현대적 프레임 워크 추세에 따라
아래와 같은 단순한 URL 주소 지원이 가능한데요.
예)
http://127.0.0.1:8000/polls/글번호/
http://127.0.0.1:8000/polls/글번호/results/
http://127.0.0.1:8000/polls/글번호/vote/

주소가 매우 간결해 보기도 좋고 그 느껴지는 분위기가 매우 우아하지 않으신가요 ? :)

이제 그 규칙을 만들어 봅시다.

polls/views.py 파일을 열어,  detail, results, vote 함수를 추가해 줍니다.

from django.http import HttpResponse

def index(request):
    return HttpResponse("투표용 서브 첫페이지.")

def detail(request, question_id):
    return HttpResponse("설문지 %s 번 페이지입니다." % question_id)

def results(request, question_id):
    response = "설문지 %s 번 결과 페이지입니다.."
    return HttpResponse(response % question_id)

def vote(request, question_id):
    return HttpResponse("귀하께서는 %s 번 설문중이시군요." % question_id)

그리고 이 함수들을 각각 URL을 연결하겠습니다.

polls/urls.py 파일을 열어 각 URL 주소를 연결해 줍니다.

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 연결을 확인해보겠습니다.
터미널에 서버가 작동중이라면 Ctrl + C 키를 눌러 중지하고 난 다음,
다시 웹 서비스를 시작합니다.

python manage.py runserver

그리고 지난 번에 추가했던 투표의 id값을 기준으로 아래와 같이 URL 에 접속합니다.
만약 id값이 4였다면 주소는 http://127.0.0.1:8000/polls/4/ 입니다.

아래와 같은 결과 페이지가 등장하였나요? 그렇다면 제대로 된 것입니다.

내친 김에 다른 URL 도 접속해 확인해볼까요?

http://127.0.0.1:8000/polls/4/results/

http://127.0.0.1:8000/polls/4/vote/

 


실제 목록 페이지

이제 실제 설문지 목록이 표시되는 페이지를 꾸며볼텐데요.
http://127.0.0.1:8000/polls/ 에 해당하는 index 함수를 수정하면 됩니다.

polls/views.py 파일에서 뒷 부분은 그대로 놔두고 앞 부분만 아래와 같이 수정합니다.

from django.http import HttpResponse
from .models import Question

def index(request):
    latest_question_list = Question.objects.order_by("-pub_date")[:5]
    output = "<br/>".join([q.question_text for q in latest_question_list])
    return HttpResponse(output)
    
    :

그리고 http://127.0.0.1:8000/polls/ 페이지에 접속하면
지난 게시글의 장고 인터프리터처럼 2개의 설문지 목록이 나열됩니다.
실제 데이터가 홈페이지에 표시가 된 것이지요.

하지만 이 것은 장고의 기능을 제대로 발휘한 것이 아닌데요.
장고는 MVC 패턴에 따라 장고 개발자가 다룰 기능 파일과
퍼블리셔가 다룰 HTML 파일을 분리할 수 있습니다.
이 HTML 파일을 템플릿이라고 합니다.
디자인을 예쁘게 하려면 HTML 소스가 길어지기 때문에
복잡성을 낮추기 위해서라도 이 부분은 매우 중요합니다.

템플릿을 분리해보도록 합시다.
템플릿 파일을 저장할 폴더를 먼저 생성해야 하는데요.|
polls 폴더 하위에 templates 폴더를 만들고 다시 그 하위에 polls 폴더를 생성합니다.
그리고 그 하위에 index.html 파일을 만듭니다

금방 만든 polls/templates/polls/index.html 파일을 아래와 같이 꾸며줍니다.

<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <title>설문 목록</title>
  </head>
  <body>
    <h1>설문 리스트</h1>
{% if latest_question_list %}
    <ul>
    {% for question in latest_question_list %}
        <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>설문 목록이 없습니다.</p>
{% endif %}
  </body>
</html>

그리고 polls/views.py 파일의 앞 부분을 아래와 같이 수정하면 되는데요.

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

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))
    
    :

이 후 http://127.0.0.1:8000/polls/ URL 에 접속하면 아래와 같이 예쁜 설문 목록이 표시되는 것을 볼 수 있습니다. 

소스는 되도록 간결하면 더 좋은데요.
장고의 shortcuts 모듈을 이용하면 더욱 소스가 간결해 집니다.

polls/views.py 파일의 앞 부분을 아래와 같이 수정해도 동일하게 작동합니다.

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

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)
    
    :

이제 설문 항목 페이지를 꾸며보겠습니다.
선택 기능은 나중에 구현하기로 하고, 설문 제목과 설문 항목을 보여주기만 할텐데요.

이를 위해 detail.html 템플릿 파일을 먼저 추가합니다.

polls/templates/polls/detail.html

<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <title>설문 목록</title>
  </head>
  <body>
    <h1>{{ question.question_text }}</h1>
    <ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }}</li>
{% endfor %}
    </ul>
  </body>
</html>

뷰에서 이 페이지를 연결해 줄텐데요.
특별히 404 오류 페이지 기능을 추가로 접목해 보겠습니다.
404 오류 페이지는 '존재하지 않는 오류 페이지'라는 뜻인데요.

존재하지 않는 투표 게시글 번호를 지정했을 때 처리를 해주는 부분입니다.

polls/view.py 파일에서
from django.shortcuts ... 라 표시된 행을 아래와 같이 수정하고,

    :
from django.shortcuts import get_object_or_404, render
    :

detail() 함수를 아래와 같이 수정합니다.

    :
def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, "polls/detail.html", {"question": question})
    :

이 것을 수정은 완료되었습니다.
이제 앞의 게시글 목록에서 무슨 일이야? 설문지를 선택하면,

아래와 같이 설문 페이지로 이동하는 것을 볼 수 있습니다.


네임 스페이스

polls/templates/polls/index.html 파일에는 아래와 같이 투표 페이지로 이동하는 링크가 '/polls/ 어쩌고로 되어 하드코딩되어 있습니다.

<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>

이러한 코드는 템플릿 파일이 많이 있는 경우 polls 폴더 이름을 바꾸려고 해도 수정할 파일이 너무 많아 엄두가 안 나는 문제가 있는데요.
처음부터 urls.py 의 urlpattern 에 정의한 name 값을 이용하면, 해당 걱정을 덜 수 있습니다.

위 소스를 아래와 같이 변경해도 기능은 동일하게 작동하는데요.

<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

그것은 urls.py 에 정의한 아래 코드 때문입니다.

path("<int:question_id>/", views.detail, name="detail"),

한 단계 더 나아가봅시다.
이 예제에서는 polls 앱 (서브 폴더) 만 존재하지만, 앱이 2, 3개 있다면 서로 이름이 겹칠 수 있습니다.

그래서 네임 스페이스를 정의하여 이름을 다음과 같이 사용할 수 있도록 해주어야 하는데요.

'polls.detail'

네임 스페이스는 app_name 으로 정의해 주면 됩니다.

urls.py 파일을 아래와 같이 수정하고,

from django.urls import path

from . import views

app_name = "polls"

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"),
]

index.html 파일의 링크도 아래와 같이 수정합니다.
이제 기능은 동일하게 작동합니다.

<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>

필요하신 분에게 도움이 되셨는지 모르겠습니다 :)
오늘은 글을 2개나 올리네요. 방문해주신 모든 분들께 감사드립니다.