#7. 사전공부 - Django 튜토리얼 따라하기 (View 만들기)

나른한 개발자·2021년 12월 16일
0

studylog

목록 보기
7/45
  1. 뷰 추가하기
  2. 템플릿 추가하기
  3. 404 에러 일으키기
  4. 템플릿에 하드코딩된 URL 제거하기
  5. 네임 스페이싱

1. 뷰 추가하기

지난번에는 index 뷰만 추가하여 간단한 문장을 브라우저에 띄워보았다. 이번에는 몇가지 뷰를 더 추가해 보도록 하자.

def details(request):
	return HttpResponse("You're looking at question %s." % question_id)
    
def results(request):
	response = "You're looking at the results of question %s."
    return HttpResponse(response % question_id)
    
def vote(request):
	return HttpResponse("You're voting on question %s." % question_id)

이렇게 뷰를 추가하였으면 polls/urls.py에 path()에 추가하여 적절한 요청이 들어왔을 때 뷰로 연결될 수 있도록 해야한다.

from django.urls import path
from . import views
urlpatters[
	path('', view.index, name='index'),
        path('<int:question_id/>', view.detail, name='detail'),
        path('<int:question_id/results>', view.results, name='results'),
        path('<int:question_id/vote>', view.vote, name='vote'),
]

이렇게 패턴들을 명시해주면 url 요청이 들어올때 적절한 뷰를 연결해 줄것이다.

예를 들어 polls/23이라는 요청이 들어왔다고 할 때, 장고는 newsite/urls.py를 불러와 urlpatterns라는 변수를 찾은 뒤 polls/ 와 일치하는 패턴을 찾는다. 찾은 뒤엔 /23에 주목하여 polls/urls.py 내에 일치하는 패턴을 찾아 view와 연결한다.

<>안의 int는 패턴의 converter역할을 하고 question_id는 패턴들을 식별하는데에 쓰일 것이다.

2. 템플릿 추가하기

여기까지는 단순히 내가 직접 입력한 문자열만 보이도록 되어있는데 이제 전에 정의한 모델 내의 데이터들을 출력할 수 있도록 해볼 것이다.

다음과 같이 작성하여 질문을 최신 순서대로 나열해 출력할 수 있도록 작성하였다.

def index(request):
	latest_question_list = Question.object.order_by('-pub_date')[:5]
    	output = ', '.join([q.question_text for q in latest_question_list])
    	return HttpResponse(out)

이것이 이제 화면에 띄워지게 될텐데 그 전에 템플릿을 추가하여 화면에 보여지는 디자인을 정의해보도록 하자.

polls앱 밑에 templates라는 디렉토리를 추가하고 그 안엔 polls/index.html을 추가한다. templates라는 디렉토리 안에 또 polls 디렉토리를 생성하는 이유는 다른 앱에 같은 이름을 가진 템플릿이 있을 경우에 구분하기 위해서 이다.

간단한 실습을 위해 다음과 같이 polls/templates/polls/index.html을 작성해준다.

{% 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>No polls are available.</p>
{% endif %}

이렇게 템플릿을 정의해줬다면 이번엔 방금 작성한 index 뷰도 수정을 해줄 것이다. 그 이유는 방금처럼 작성을 하면 물론 내용은 제대로 보이겠지만 화면에 데이터가 띄워지는 방식도 함께 정의되어있는 것과 마찬가지이다. 따라서 나중에 디자인을 바꾸려한다면 뷰도 함께 수정을 해야하는 번거로움이 발생한다.

코드에서 디자인 부분을 분리하기 위해 뷰를 다음과 같이 수정해보자.

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

def index(results):
	latest_question_list = Question.object.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))

context는 템플릿에서 쓰이는 변수를 객체로 연결하는 사전형 값이다.
이렇게 작성을 해주면 polls/index.html 템플릿을 불러와 context를 넘겨주고 템플릿에 정의된 대로 렌더링이 될 것이다.


여기서 모든 뷰에 다른 stub 메서드가 없이 똑같이 적용한다면 loader와 Http를 임포트 할 필요 없이 render()로만 작성을 할수 도 있다.

from django.templates import render

from .models import Question

def index(request):
	latest_question_list = Question.object.order_by('-pub_date')[:5]
    	context = {'latest_question_list':latest_question_list}
        return render(request, 'polls/index.html', context)
    

3. 404 에러 일으키기

존재하지 않는 id에 대한 요청이 들어올 때 404 에러를 띄울 수 있도록 해보자.

<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>

우선 위와 같이 detail.html 템플릿에 다음과 같이 작성해 준 뒤 아래 처럼 에러처리 구문을 뷰에 추가하면 존재하지 않는 id를 요청할 경우 404에러를 볼 수 있을 것이다.

from django.http import http404
from django.templates import render

from .models import Question

def detail(request, question_id):
	try:
    		question = Question.object.get(pk=question_id)
    	except Question.DoesNotExist:
    		raise Http404("Question does not exist")
    	return render(request, 'polls/detail.html', {'question': question})

또는 get_object_or_404()를 이용해 다음과 같이 작성할 수도 있다.

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)
    	return render(request, 'polls.detail.html', {'question': question})
    

get_object_or_404()는 모델을 첫번째 인자로 받고 나머지 키워드 인수를 모델 관리자의 get()에 넘긴다. 이때 존재하지 않을 경우 에러를 발생시킨다.
이 방법을 쓰면 더 간략해 질 뿐만 아니라 약결합으로 코드를 짤 수도 있어 좋은 방법인 것 같다.

이밖에도 리스트로 받아야하는 것이면 get_list_or_404() 함수를 쓸수도 있는데 이는 get()함수가 아니라 filter()함수에 인수를 넘긴다.

4. 템플릿에 하드코딩된 URL 제거하기

위에서 템플릿에 URL을 작성한 부분이 있는데 이것도 사실 특정 url을 지정해버리면 나중에 수정을 하기가 매우 까다롭기 때문에 다음과 같이 작성하는 것이 보다 효율적이다.

<!--바꾸기 전-->
<li><a href='/polls/{{question_id}}/'>{{question.question_text}}</a></li>

<!--바꾼 후-->
<li><a href="{%url 'detail' question.id %}">{{question.question_text}}</a></li>

polls/urls.py에서 path에 이름을 정의해 놓은 것을 토대로 위와 같이 작성을 한다. 이러면 urls.py에 정의된 url을 탐색하는 식으로 동작하게 되고 낮은 의존성을 유지할 수 있다.

5. 네임 스페이싱

앞서 템플릿을 만들 때 polls앱에 templates/polls/index.html 처럼 앱의 templates이라는 디렉터리 안에 앱의 이름을 가진 디렉터리를 하나 더 생성해주었다. 여러가지 앱이 동일한 이름의 템플릿을 가질 때 이를 구분하기 위해서인데, 이렇게 디렉터리를 추가하지 않고도 장고가 이를 구분하도록 하는 방법이 바로 네임 스페이싱이다.


app_name = 'polls'
urlpatterns=[ ...이하생략...]

위와 같이 polls/urls.py에 이름을 써주고 템플릿에도 상세 뷰를 가리킬 수 있도록 수정해주면 된다.

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




이렇게 오늘은 뷰를 생성하고 템플릿까지 추가하는 것을 해보았다. 오늘은 이전 시간보다 이해하는게 조금 힘들긴했지만 그래도 차근히 하니까 감이 오는 것 같다.

또한 오늘 공부 내용 중에서 하드 코딩을 효율적인 코드로 바꾸는 것을 했는데 코드를 작성함에 있어 의존성을 낮게 유지하는 게 얼마나 중요한지 다시금 느꼈고 그 방법까지 알 수 있어서 좋았다. 지금은 작은 실습이라 큰 영향은 없겠지만 일정 규모의 프로젝트를 하게 되면 분명히 높은 의존성 때문에 문제가 생길 것이다.

오늘 한 내용은 좀 중요도도 높고 어려우니 다음 실습 들어가기 전에 좀 더 머리에 새겨야 할 것 같다.


다음에도 빠샤!! 🔥

profile
Start fast to fail fast

0개의 댓글