티스토리 뷰

Tech Stack Diagram


(https://rubygarage.org/blog/technology-stack-for-web-development)


웹 사이트를 만들겠다고 하면, 클라이언트 사이드 (프론트엔드) 와 서버 사이드 (백엔드) 두 부분을 고려해야 한다.


클라이언트 사이드를 만들기 위한 언어는 예나 지금이나 HTML, CSS, 자바스크립트로 변함이 없다. jQuery부터 시작해서 AngularJS니 React니 Vue.js니 하는 신기술들이 끊임없이 나오는 것 같지만 쟤네는 근본적으로 다 자바스크립트랑 관련된 것들이다 (라이브러리나 프레임워크라고 하는데 안 써봐서 잘은 모르겠다).


서버 사이드는 좀 다르다. 

내가 학부생이었던 시절만 해도 (그렇게 막 오래된 것두 아니구 5~6년 전) 웹 사이트 만드는 과제가 있으면 PHP를 많이 썼다. WAMP 스택 (Windows OS에 Apache 웹 서버, MySQL 데이터베이스, PHP 서버사이드 프로그래밍 언어) 을 편리하게 구축할 수 있게 도와주는 프로그램들이 많이 있었기 때문에 접근성 측면에서 단연 최고였다.

자바를 이용한 JSP도 많이 썼다. 자바야 학부 커리큘럼에 당연히 있으니 진입장벽이 낮기도 했고, 과제하면서 쓸 기회가 많았던 자바 라이브러리들도 다 끌어다 쓸 수 있었다.

그 외에 ASP라는 것도 많이 썼다는데 써보진 않았다. 여튼 수년 전까지만 해도 웹 사이트를 만든다고 하면 서버 사이드는 P로 끝나는 이 세 가지 언어가 주로 언급됐던 것 같다.


요즘은 상황이 많이 변한 것 같다. 물론 PHP와 JSP의 점유율은 여전히 높다. 특히 JSP같은 경우는 이걸 이용하는 Spring이라는 프레임워크가 한국 전자정부 표준 기술이라고 한다. 망할 리가 없다.

그렇지만 요즘은 훨씬 더 다양한 언어가 서버 사이드 웹 개발에 쓰인다. 클라이언트 사이드 언어로 여겨졌던 자바스크립트가 Node.js라고 해서 서버 사이드 언어로 쓸 수 있게 됐고, 루비나 파이썬도 웹 개발에 많이 쓰이게 됐다. 오히려 예전에 가장 많이 쓰였던 PHP는 최신 트렌드를 따라가는 개발자들 사이에서는 까야 제맛 수준의 언어로 전락했다. (...)


django logo에 대한 이미지 검색결과


파이썬으로 서버 사이드 웹 개발을 할 수 있도록 도와주는 프레임워크가 오늘 배워볼 django (장고) 다. d로 시작하지만 장고라구 읽는다. 묵음의 세계는 여전히 오묘하다.

프레임워크라는 것은 쉽게 얘기하면 편리한 개발을 위해서 일반적으로 필요할 만한 것들을 묶어서 제공해주는 도구 같은 것인데, 예를 들어서 웹 개발을 한다면 일반적으로 회원가입을 하고 회원 데이터를 관리하며 링크를 눌러서 다른 페이지로 이동하고... 이런 요소들이 들어갈 것이다. 그러니까 그런 것과 관련된 클래스, 라이브러리를 묶어서 제공해주는 것이다.


왜 장고를 배워볼 생각을 하게 됐냐면 JSP를 처음 접했을 때랑 비슷하게... 파이썬에서 쓸 수 있는 라이브러리를 내가 만들고 싶은 웹 사이트에 갖다 쓰고 싶었다. 최근에 쭉 파이썬만 해오기도 했고, 머신러닝같은 분야는 특히 파이썬 라이브러리가 많구.


그럼 장고를 시작해보자.




1) 가상 환경 및 장고 설치


장고를 설치하려고 여기저기 알아봤는데, 하나같이 장고를 설치하기 전에 가상 환경 (Virtual Environment) 이라는 걸 설치할 것을 권장하더라.


이 가상 환경이란게 뭐냐면 폴더를 하나 만들어서 그 안에 작은 파이썬 환경을 새로 만드는 것이다. 그러니까 이 가상 환경 안에서 작업을 하면 기존에 컴퓨터에 깔아놨던 파이썬 라이브러리나 설정들에 영향을 미치지 않는다. 반대로 말하면, 이 안에서 파이썬 라이브러리를 쓰고 싶으면 이 안에서 새로 깔아야 한다.


외부와 격리된 독립적인 환경을 만들겠다는 취지는 알겠는데 왜 다른 파이썬 프로그램들 깔때는 전혀 보도 못한게 장고 깔때만 꼭 설치하라고 하는건지는 잘 모르겠다. 웹 프레임워크라는게 잘못 건들면 다른 곳에 막 영향을 미치고 그런 특성이 있나? 시간나면 알아보자.


여튼 이 가상 환경은 최신 버전 파이썬에는 기본적으로 내장되어 있지만, 내 컴퓨터에 깔려있는 파이썬은 여전히 2.7 버전이다.

2.7 버전에서는 가상 환경을 만들기 위한 패키지를 따로 설치해줘야 한다. pip로 설치해주자.


pip install virtualenvwrapper-win


다음으로 가상 환경을 만들어보자. 기본적으로 자기 컴퓨터에서 지금 접속중인 계정의 홈 폴더에 Envs라는 폴더를 생성한다.

예를 들어서 계정 이름이 'user' 라면 C:\Users\user\ 에 생성된다.


mkvirtualenv [만들가상환경이름]



나는 계정명이 Yukkuri고 djangoproject라는 가상 환경을 만들었다. 현재 가상 환경 안에서 작업중이라는 것을 왼쪽의 괄호를 통해서 알 수 있다.


명령 프롬프트를 닫았다가 다시 켜면 가상 환경 밖으로 빠져나오게 되는데 다시 가상 환경에 재접속하려면 아래의 두 명령어 중 하나를 입력한다.


workon [가상환경이름]

(가상환경 폴더 내의 Scripts 폴더 안에서) activate


이제 가상 환경이 세팅되었으니 가상 환경 안에서 장고를 설치해주자.


pip install django


장고도 여러 버전이 있는데, 내 파이썬 버전에 맞게 pip가 알아서 결정해준다.

현재 지원이 계속되고 있는 장고 버전은 1.11, 2.0, 2.1이 있는데 1.11은 파이썬 2.7을 위한 버전이고 2.0, 2.1은 파이썬 3.x를 위한 버전이다. 장고 2.x는 계속 꾸준히 신버전이 나오겠지만 1.11은 파이썬 2.7의 지원이 종료되면 머지않아 같이 지원이 종료될 것이다 (홈페이지에 따르면 2020년 4월 쯤). 

가급적 2.x를 쓰면 좋겠지... 만 파이썬 3으로 바꾸기가 너무 귀찮기 때문에 일단 1.11로 배워보기로 하자... 이럴때마다 느끼는건데 참 최신 트렌드 따라가기 어렵고 자괴감 든다ㅠ




2) 장고 튜토리얼 따라하기


장고를 깔긴 깔았는데 어떻게 써야 하는지 뭐부터 해봐야할지 너무 막연하다.

다행히 장고 공식 페이지에서 튜토리얼을 제공하는데, 1.11 버전에 대한 백업도 되어 있고 한글 문서도 있다. 이 튜토리얼을 차근차근 따라가보면서 기본적인 장고 사용법과 개념을 익혀보자.


https://docs.djangoproject.com/ko/1.11/intro/tutorial01/


2-1) 프로젝트 만들기


여느 개발 환경이 그렇듯 장고에서도 '프로젝트' 라는 단위가 있어서 일단 개발을 시작하려면 프로젝트부터 만들어야 한다.

mysite라는 이름의 프로젝트를 만들어보려면 아래와 같이 입력한다.


django-admin startproject mysite


현재 디렉토리에 mysite라는 폴더가 생길 것이다. 안에 들어가보면 mysite라는 폴더가 하나 더 있고, manage.py라는 파일이 있고, 안쪽 mysite 폴더 안에는 py 파일 4개가 또 있다.


각각의 역할에 대한 간략한 설명은 아래와 같다.


> manage.py: 장고 프로젝트와 통신하기 위한 커맨드라인 유틸리티. 즉 cmd 창에서 직접 실행할 일이 많다

> 안쪽 mysite/ 폴더: 내 프로젝트의 실제 파이썬 패키지 이름. 안쪽에 있는 파일들에 mysite.urls 와 같이 접근할 수 있다

> __init__.py: 파이썬에게 이 디렉토리가 파이썬 패키지다라는 것을 알려주는 역할

> setting.py: 이름 그대로... 장고 프로젝트에 대한 설정 파일

> urls.py: 이 장고 프로젝트가 포함하는 URL들을 정의. 장고 사이트의 목차 같은 역할

> wsgi.py: '웹 서버 게이트웨이 인터페이스' 의 줄임말인데 웹 서버랑 관련된 역할을 하는 듯


좀 더 구체적으로 어떻게 쓰이는지는 하다보면 더 알게 될 것 같다.


만들어진 프로젝트에는 기본 페이지가 들어있으니, 장고 프로젝트가 제대로 생성됐는지 확인할 겸 기본 페이지를 띄워보자.

웹 서버를 돌리려면 Apache 웹 서버나 nginx 같은 걸 깔아야하지 않느냐... 라고 생각할 수도 있는데, 따로 깔아서 연동해줘도 되지만 테스트용이라면 가볍게 쓸 수 있는 기본 웹 서버가 장고에 내장되어 있다.


(바깥쪽 mysite 폴더 안에서) python manage.py runserver


기본적으로 설정되어 있는 주소는 127.0.0.1:8000이다. 여기로 접속했을 때 기본 페이지 (worked 어쩌구 하는) 가 뜨면 성공.


2-2) 앱 만들기


앱 (App) 은 프로젝트보다 좀 더 작은, 웹 사이트의 특정한 기능을 구현하는 단위이다. 프로젝트는 앱과 설정들의 집합으로 정의한다.

mysite라는 프로젝트 안에 polls라는 앱을 만들어보자. 이름을 보면 설문조사나 투표 같은걸 할 수 있는 웹 사이트일 것 같다.


python manage.py startapp polls


polls라는 폴더가 생기고, 기본적으로 안에 생기는 파일들은 다음과 같다.


__init__.py

admin.py

apps.py

migrations 폴더 -> __init__.py

models.py

tests.py

views.py


2-3) 뷰와 URL 설정


뷰에 대해서 얘기하기 전에, MVC 패턴이라는 용어를 짚고 넘어가자.


장고는 MVC (Model-View-Controller) 패턴이라는 디자인 패턴에 따라 만들어졌다. MVC 패턴이 뭐냐면 사용자가 보는 인터페이스와 내부 동작 (비즈니스 로직), 그리고 데이터베이스가 서로 독립적으로 구성되어 한 쪽이 수정되더라도 다른 쪽에 영향을 주지 않는 설계를 의미한다.

Model은 데이터베이스, View는 인터페이스, Controller는 비즈니스 로직을 의미한다.


단 장고에서는 이를 칭하는 용어가 좀 다른데, '모델' 은 그대로지만 MVC 패턴에서의 컨트롤러 역할을 하는 것이 장고에서는 '뷰' 이다. 그리고 MVC 패턴에서의 뷰 그러니까 인터페이스 역할을 하는 것은 장고에서는 '템플릿' 이라 부른다.


MVC 패턴을 차용했다면서 쓸데없이 View라는 용어가 서로 다르게 쓰이고 있어서 혼동을 유발한다. 어쨌든 그렇단다.


일반 용어

MVC 패턴

장고

데이터베이스

Model

Model

인터페이스

View

Template

비즈니스 로직

Controller

View


다시 장고로 돌아와서, 그러니까 뷰라는 것은 웹 페이지에서 무슨 일을 할지를 파이썬 코드로 표현하는 부분을 의미한다.


우리가 만들 polls 앱에서 기본 페이지 대신에 뭔가 새로운 페이지를 띄우도록 만들어 보자.


- view.py 파일을 다음과 같이 수정

from django.http import HttpResponse


def index(request):
    return HttpResponse("Hello, world. You're at the polls index.")

view.py 안에 들어가는 함수 하나하나가 '뷰' 가 된다. 즉 여기에서는 index라는 이름의 뷰를 만든 것이다.


근데 뷰만 달랑 만들면 끝나는게 아니라, 뷰를 호출하기 위한 URL을 연결시켜줘야 한다.

여기서 만들어주는 것을 URLconf라고 하는데 아래의 urls.py 파일에 정의해줘야 한다.


- urls.py라는 파일을 polls 폴더 안에 생성하고 다음과 같이 코딩

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
]

구조를 보면 urlpatterns라는 리스트가 있고, 그 안에 url() 이라는 메소드가 있다.

url() 메소드는 3개의 인자를 받고 있다. 각각 설명하면 이렇다.


> 첫번째 인자 (regex): 정규 표현식. URL의 패턴을 찾아내기 위해 쓴다.

> 두번째 인자 (view): 위에서 view.py라는 파일 안에 index라는 함수 즉 뷰를 만들었다. 이를 views.index와 같이 가리킨다.

> 세번째 인자 (name): 해당 URL에 대해 유니크한 이름을 부여해줘서 장고 프로젝트의 다른 부분에서 찾을 수 있게 한다. optional.


이걸로 끝나는게 아니고 프로젝트 최상단으로 올라가서 또 polls/urls.py를 참조하도록 만들어줘야 한다.


- mysite/urls.py로 가서 다음과 같이 수정

from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
    url(r'^polls/', include('polls.urls')),
    url(r'^admin/', admin.site.urls),
]

include('polls.urls') 가 polls/urls.py라는 파일을 참조하겠다는 뜻이다.

여기서 include() 라는 함수가 사용됐는데 앞의 인자를 보다가, 뒤에 include가 있으면 나머지 부분은 그 파일로 넘겨주는 모양이다.


ex) /polls/some/method 라는 요청이 들어오면 /polls/ 는 앞의 인자에 있으니까 자기가 인식하고 나머지 /some/method는 polls/urls.py로 넘겨준다.


위의 파일을 보면 현재 상태가 어떻냐면, localhost:8000/polls/ 라는 경로랑 localhost:8000/admin/ 라는 경로가 정의되어 있다.

그리고 polls로 들어가게 되면 polls.urls를 보는데 여기 정규표현식을 보면 ^$라고 써있다. 정규표현식 배운지가 까마득해서 뭔지 기억이 안나는데, 그냥 localhost:8000/polls/ 로 들어가게 되면 index 뷰가 뜨는 걸로 봐서는 아무것도 아닌 모양이다.


여기까지 해놓고 localhost:8000/polls/ 로 들어갔을 때 헬로월드 어쩌구 하는 텍스트가 뜨면 성공이다.


2-4) 모델과 마이그레이션


MVC 패턴에서도 설명했듯 모델이란 곧 데이터베이스를 뜻한다. 장고에서 데이터베이스를 다루는 방법에 대해서 알아보자.


장고에는 기본적으로 SQLite가 내장되어 있다. 안드로이드에서도 기본으로 쓰는 그거 맞다.

좀 더 본격적인 DBMS를 쓰려면 PostgreSQL, MySQL, Oracle 등을 지원하는데 따로 깔아서 연결해줘야 한다.

일단 지금은 연습용이니까 그냥 내장된 SQLite를 쓰자.


- 모델 생성: polls/model.py 라는 파일을 다음과 같이 편집

from django.db import models


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')


class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

클래스가 각 테이블이라 생각하면 되고 models.Model이라는 슈퍼클래스로부터 상속을 받는다.


question_text, pub_date 라는 속성을 가진 Question 테이블, 그리고 question, choice_text, votes라는 속성을 가진 Choice 테이블을 생성하는 코드이다. 필드는 django.db.models.XXXField 이런 식으로 생겼다 (XXX는 타입).

Foreign Key를 설정하는 코드도 있는데 각각의 Choice가 하나의 Question에 관계된다는 의미다.


model.py를 코딩하긴 했는데 저렇게 써놓는다고 바로 데이터베이스에 저게 반영되는게 아니다.


여기서 '마이그레이션' 이라는 용어가 나오는데, 일반적으로는 '이주/이동' 같은 의미지만 장고에서는 모델의 변경 사항을 의미한다.

'makemigrations' 라는 명령어를 쓰면 변경 사항에 대한 기록 즉 마이그레이션을 생성할 수 있고,

'migrate' 라는 명령어를 통해 아직 DB에 적용되지 않은 마이그레이션들을 반영하는 과정을 거치게 된다.


마이그레이션을 만들기 전에 먼저 해줘야 할 일이 또 있는데, 현재 프로젝트, 데이터베이스에게 polls 라는 앱이 설치되어 있다는 것을 알려주기 위해서 setting.py 파일을 업데이트해줘야 한다.


setting.py 파일의 INSTALLED_APPS 안에다가 polls.apps.PollsConfig 라고 추가해준다.

(PollsConfig는 polls/apps.py 안에 존재하는 클래스 이름임. 그래서 위와 같이 점으로 구분된 경로가 나온다)


그 다음은 위에서 설명한 것처럼 마이그레이션을 만들고 반영해 준다.


python manage.py makemigrations polls

python manage.py sqlmigrate polls 0001

python manage.py migrate


중간에 들어간 sqlmigrate라는건 옵션인데, 만들어놓은 마이그레이션이 실제로 어떤 SQL 쿼리문을 수행할지 확인할 수 있는 명령어다.


Create model Choice

-> CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL);


만든 클래스 이름 앞에 app 이름이랑 언더바가 자동으로 붙고, "id" 라는 컬럼은 자동으로 생성해주는 것을 확인할 수 있다.


정리하면 장고에서 데이터베이스 즉 모델을 변경할 때마다 다음과 같은 3 Step을 거친다.


> models.py 파일을 에디트하여 모델을 변경한다

> makemigrations 명령으로 이 변경사항에 대한 migration을 생성한다

> migrate 명령으로 2) 에서 만든 migration을 데이터베이스에 적용한다


2-5) Admin 페이지 살펴보기


장고는 웹 프레임워크라고 했듯 데이터베이스 관리와 같은 웹 사이트에 기본적으로 필요한 기능을 자체적으로 제공한다.

PHP를 써봤으면 phpmyadmin이라는 도구가 친숙할텐데 그런 비슷한 느낌이다.


- Admin 계정 만들기


python manage.py createsuperuser


관리자 계정을 만든 다음 서버 켜고 localhost:8000/admin/ 으로 들어가면 관리자 페이지 로그인 화면이 뜬다.

아이디랑 비밀번호를 치고 로그인을 하면 관리자 페이지 메인 화면이 뜨는데...


만들어놓은 데이터베이스에 대한 정보가 안 보인다.


polls/admin.py 라는 파일을 수정해줘야 polls 앱에 대한 내용을 관리자 페이지에서 다룰 수 있게 된다.

from django.contrib import admin from .models import Question admin.site.register(Question)    // Choice까지 다루고 싶다면 ([Question, Choice])

이렇게 수정하고 다시 접속해보면 polls 앱과 그 안에 존재하는 테이블 리스트가 뜬다.


2-6) 뷰와 템플릿


설문조사를 하기 위한 페이지를 본격적으로 더 만들어보자.


- polls/views.py 파일을 다음과 같이 수정

def detail(request, question_id):
    return HttpResponse("You're looking at question %s." % question_id)

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

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

뷰는 비즈니스 로직, 즉 파이썬 코드를 이용해서 웹 페이지에서 뭔가 일을 하게 만드는 부분이라고 했다. 이 예제에서는 단순히 텍스트 한 줄만 띄우지만, 일반적으로 파이썬 프로그래밍을 배울 때 했던 것들을 저기다 얼마든지 끼워넣을 수 있다. 라이브러리도 갖다 쓸 수 있고.


그리고 공통적으로 보면 HttpResponse라는 걸 반환하는데, 뷰는 궁극적으로는 HttpResponse를 반환하던지 Http404 같은 예외를 발생시키던지 둘 중 하나를 하게 된다. 예외를 발생시키는 방법은 뒤에서 알아보자.


그럼 앞에서 했듯 만들어준 뷰들에 대한 URLconf를 만들어주자.


- polls/urls.py 파일을 다음과 같이 수정

urlpatterns = [
    # ex: /polls/
    url(r'^$', views.index, name='index'),
    # ex: /polls/5/
    url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
    # ex: /polls/5/results/
    url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
    # ex: /polls/5/vote/
    url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]

정규표현식을 보면 <question_id>[0-9]+ 라는 부분이 있는데, <>에다가 변수 이름을 집어넣으면 인식하는 모양이고, [0-9]+ 는 정규표현식에서 n자리의 숫자를 의미한다.


접속해보면 제대로 뜰 것이다.


근데 페이지에 자꾸 텍스트 한 줄만 달랑 뜨니까 뭔가 섭섭하기도 하고, 더 복잡한 페이지를 만들려면 저 views.py에다가 모든 페이지 내용을 코딩해야 하나? 라는 생각이 들 수 있다.


사실 생각해보면 보통 웹 페이지의 기본은 HTML이다. 뷰에서 HTML 파일을 가져와서 뿌려주는 것이 가능하고, 이걸 템플릿이라 부른다.

MVC 패턴에서 얘기했던 대로 웹 페이지의 디자인, 인터페이스적 요소는 HTML 파일로 분리하자.


- polls 안에다가 template이라는 폴더를 만들고 그 안에 또 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 %}

딱 보면 뭔가 HTML 문법도 있긴 한데 파이썬 코드도 섞여있고 그런 혼종처럼 보인다. {% %} 나 {{ }} 로 감싸져있는 부분은 파이썬 코드인 것 같고, 나머지는 HTML 코드다.

생각해보면 PHP에서도 <? ?> 같은 식으로 HTML 파일 안에다가 끼워넣어서 PHP에서 변수를 가져오는 그런 것들이 가능했다. 이것도 같은 원리일 것 같다.

그럼 latest_question_list라는 변수를 파이썬 코드에서 가져와야 할 것 같다.


- views.py에서 index 뷰에 대한 코드를 수정

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

index 함수 첫번째 줄부터 보면 Question에서 object를 가져오는데 pub_date 순으로 정렬해서 5개 갖고온다. 데이터베이스를 다루는 API다.

두번째 줄이 polls/index.html 이라는 파일을 갖고와서 띄워주는 부분인 것 같고 여기서 loader라는게 쓰인다.

세번째 줄을 보면 context라는 dict가 있는데, 위의 index.html 파일로 latest_question_list 변수를 넘겨주는 역할이다.


여기까지 하고 localhost:8000/polls/ 로 접속하면 "No polls are available." 메시지가 뜰 것이다.

데이터베이스에 아무것도 추가해주지 않았으니 당연하다.

관리자 페이지로 가서 Question을 몇개 추가해준 다음 다시 접속하면 리스트가 뜬다.



다음으로 요청한 페이지가 없을 때 404 (Not Found) 에러를 발생시키는 방법을 알아보자.


- views.py의 detail 뷰 수정

from django.http import Http404
from django.shortcuts import render

# ...
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})

'raise Http404("Question does not exist")' 부분이 예외를 발생시키는 부분이다. 어차피 텍스트 띄우는건 똑같지 않냐고 생각할 수도 있겠지만 HTTP 헤더 코드에 404를 넣어 보낸다는 점이 의미있는 것이다.


그리고 return 문을 보면 render 함수가 사용되고 있는데, 위 예제에서 context에 변수를 넣은 다음 HttpResponse를 리턴하는 두 과정을 한줄로 합친 코드다. 자주 쓰이는 용법이기 때문에 줄여서 쓸 수 있게 해놨다.


- detail.html 이라는 파일을 만들고 아래와 같이 코딩

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

이렇게 만든 다음 localhost:8000/polls/1/ 로 들어가본다.

Question이 3까지 있으니까 1은 제대로 뜨겠지만, 5를 넣으면 아래 사진과 같이 404 에러가 뜬다.



위의 render() 함수와 마찬가지로 404 에러 발생시키는 것도 자주 쓰는 용법이라 줄여서 쓰는 방법이 있다.

위의 detail 뷰에서 try-except 문 대신에 이거 한줄만 써줘도 된다.


question = get_object_or_404(Question, pk=question_id)


2-7) 템플릿 태그 'url' 과 네임스페이스


아까 index.html 파일을 보면 이런 부분이 있었다.

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

이 코드의 문제점은 앞에 /polls/ 라는 하드코딩된 부분이 있다는 건데, 당장은 상관없지만 템플릿을 엄청 많이 만든 상태에서 URL이 바뀌기라도 하면 저걸 다 고치기가 어렵다는 점이다.

이걸 어떻게 바꿀 수 있냐면, 앞의 urls.py에서 URL 패턴 정의할 때 'name' 이라는 속성을 만들어 줬었다. 그걸 써먹는다.

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

여기서 % 다음에 url이라고 쓰는데 이런걸 템플릿 태그라고 부르는 모양이다.

polls/urls.py 안에 아래와 같은 코드가 있기 때문에 가능한 방법이다. name='detail' 을 보고 이 URL 패턴을 찾아가는 것이다.

url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),

이 detail 뷰의 URL을 /polls/5/ 가 아니라 /polls/specific/5 로 바꾸고 싶다면 아래와 같이 한다.

url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),

근데 생각해보면 'detail' 이라는 이름은 굉장히 흔하다.

지금은 polls라는 앱 하나만 만들었는데, 장고 웹 프로그래밍을 하다보면 앱이 더 많이 만들어질 수 있고 여러 앱에서 detail이라는 이름을 써야하는 상황이 생길 수도 있다.

이럴 때 쓰라는 것이 네임스페이스인데 urls.py에서 URL 패턴 위에다가 app_name이라는 변수를 하나 추가해준다.

app_name = 'polls'
urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
    url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
    url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]

그 다음, index.html의 템플릿 태그 들어가는 부분을 아래와 같이 바꿔준다.

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

이러면 앱이 polls 말고 여러 개 더 있다고 해도, 저 url 템플릿 태그가 polls라는 앱의 detail이라는 이름을 가진 URL 패턴을 찾아가라는 의미로 해석을 하게 된다.




여기까지가 튜토리얼 1~3장의 내용을 정리한 것이다.

4, 5, 6장도 있긴 한데 일단 여기까지 내용만 가지고 뭔가 다른 걸 하나 만들어볼지, 아니면 튜토리얼을 계속 따라가볼지 고민이다.

내일 하루는 쉬고 생각해봐야지.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함