MicroSoftware 2006-11 <특집> 대안 웹프레임워크

“장고(Django)”로 쉽고 빠른 웹 개발

이제 웹은 우리 생활의 일부가 되었다. 일상생활의 많은 일이 웹을 통해 이루어진다. 그러자니, 어떻게 하면 쉽고 빠르게 웹 어플리케이션을 만들 수 있을지 역시 많은 관심거리가 되고 있다. Ruby on rails를 필두로 하는 빠른 웹 개발 프레임워크들 속속들이 등장하고 있는 가운데 장고(Django)는 파이썬으로 만들어진 웹 프레임워크이다.

김형용 ㈜인실리코젠 개발팀

필자는 현재 생물정보 전문기업인 ㈜인실리코젠 개발팀에 근무 중이며, 생물정보 전문 위키위키인 biohackers.net을 운영하고 있다. 생명현상에 대한 남다른 관심으로 생물공학을 전공했으며, 생명과학 분야에서 프로그래밍의 가능성을 인식하고, 생물정보학을 공부하고 있다. 작고, 빠르고, 점진적인 피드백을 통한 개발방법에 관심이 많다.

서론

웹(Web)은 우리가 늘 접하는 것이면서도, 그것을 직접 만들기는 쉽지 않았다. (여기에서 웹은 데이터베이스와 연동하는 동적 웹 어플리케이션을 의미한다.) 그도 그럴 것이, 보통 웹 개발 소스 파일 하나를 열어보면, 데이터베이스 접속 코드(SQL) 부터해서, 서버 측 스크립트(PHP, CGI), 클라이언트 측 스크립트(JavaScript)에, 화면에 어떻게 보여줄지에 대한 HTML, CSS, 웹 디자인 등등 무수히 많은 정보가 스파게티처럼 섞여 있음을 알 수 있다. 더군다나, 웹은 사용자와 직접 닿아있는 부분(interface)이기에, 요구 사항도 자주 변하고, 지속적으로 관리되어야 한다. 그야말로, 프로그래밍 분야에서의 종합예술이라 할 만하다. 오늘도 많은 개발자가 HTML에, SQL에, 웹 디자인에, 야근에, 변경요구에, 머리를 아파하고 있다.

개발 경험이 많은 사람이라면, 대부분의 웹 개발이 특정 패턴이 반복적으로 계속된다는 것을 느꼈을 것이다. 데이터베이스 레코드들의 리스트를 화면에 보여주는 일, 레코드의 상세정보를 보여주는 일, 그것을 삭제하거나 수정하는 일 등등, SQL 구문에서도 계속해서 반복된 패턴이 나타나고, 그것을 보여주는 서버 측 스크립트도 그러하다. 반복은 관리를 어렵게 하고, 개발을 재미없게 한다. “에잇 참을 수 없어” 하고, 이 반복되는 것들을 DRY(Don’t Repeat Yourself)의 법칙에 따라 적절하게 리팩토링하고, 추상화하면 쉽게 재사용 가능한 코드를 예상할 수 있다. 웹 프레임워크란 바로 이런 것이다. 개발경험이 많은 사람이 디자인 패턴리팩토링의 원칙에 따라 웹 개발의 반복적인 부분들을 추상화한 것이다. 더불어서, Ruby on rails를 필두로 하는 근래의 웹 프레임워크들은 “똑똑한 디폴트(default)”를 제공하여, 최소의 설정만으로도 웹사이트 구현이 가능하도록 지원함으로써, 가능한 한 쉽고 빠르게 웹 사이트를 만들 수 있게 한다.

장고(Django)는 그 가운데에서도, 파이썬([Python])으로 만들어졌으며, 가능한 독립적으로 동작 가능하도록 설계된 웹 프레임워크이다.

장고의 특징

파이썬은 이제는 대안 언어가 아니다. 구글(Google)을 비롯한 많은 기업이 그 쉽고, 강력함에 매료되어, 그 사용빈도를 계속해서 높이고 있다. 실제 2006 대안언어축제에는 많은 참가자와 발표자들이 파이썬을 잘 알면서도, 발표 튜토리얼은 제공하지 않아 그 “대안” 이란 의미를 실감하게 했다. 또한 그 강력함으로 인해, 이제는 프로토타입용 언어라는 타이틀도 벗어버렸다. 많은 실험용 코드들이 몇몇 수정만으로도 실제 서비스에 이용되기도 한다. 장고는 바로 파이썬 사용자들을 위한 웹 프레임워크이다.

장고는 미국의 온라인 신문사인 World Online에서 처음 시작되었다. 2003년 가을, 계속되는 뉴스기사들의 추가, 새로운 콘텐츠의 제공 요구, 다가오는 데드라인 등의 압박에서, 아드리안과 사이몬(Django의 핵심 개발자들)은 [PHP]를 벗어버리고, 파이썬으로 웹사이트를 구현하기로 한다. 그리고는 2년 뒤인 2005년 여름, 구현된 웹사이트의 재사용된 부분들을 오픈 소스로 공개하기로 하고, 그것의 이름을 장고로 지었다. (그 이름은 아드리안이 좋아하는 재즈기타리스트인 Django Reinhardt의 이름에서 따왔다고 한다.)

웹사이트에 사용된 오픈소스 소프트웨어들인 Apache, PostgreSQL, 파이썬이 없으면, 장고도 의미가 없다는 생각에 개발자들은 장고 역시 오픈소스로 추진하였고, 그것을 자랑스러워 하였다. 그 덕분에, 우리도 이러한 좋은 프레임워크를 자유롭게 쓸 수 있게 되었으며, 전 세계의 개발자들과 함께 더욱더 발전하게 되었다. 장고는 World Online사에서 3년여 간 방대한 트래픽을 처리하면서, 안정성을 인정받았고, 폭주하는 요청들에 대한 다양한 분산 요구 사항들도 만족하면서, 실용성을 높였다. 무엇보다도, 장고의 주요 목적인 쉽고, 빠른 웹사이트 개발환경에 많은 개발자들이 매료되었고, 그 이후, 워싱턴포스트를 비롯한 주요 신문사 웹사이트에 사용되었으며, 다양한 웹 어플리케이션들을 위한 웹 프레임워크로 자리매김하였다.

파이썬과 같은 스크립트 언어로 웹 어플리케이션을 만드는 일은 몇 가지 문제들로 인해, 그 실용성에 많은 문제가 제기되어 왔다. 매 요청마다 그때그때 인터프리터가 메모리로 올라와야 했고, 그로 인한 성능저하를 감수해야만 했다. 이를 피하기 위한 다양한 방법들이 존재해 왔는데, 이는 개발자들로 하여금, 웹 프로그래밍을 더욱 어렵게 했다. 올해 10월 공개된 파이썬 2.5는 이러한 다양한 방법들에 대한 공통된 API인 WSGI(Web Server Gateway Interface)를 제공하는데, 장고는 그 이전부터, WSGI를 자체적으로 제공하여, 다양한 웹 환경에서의 동작을 가능하게 하였다. 이를 테면, Apachemod_python을 이용한다던가, ApacheFastCGI를 이용한다던가, 파이썬 비동기 네트워크 프레임워크인 Twisted의 web2를 이용한다던가, 등등이 모두 가능하다.

근래의 소프트웨어들은 그 설계에 있어서, 모델(데이터)와 뷰(보여주는 방법)을 분리하는, MVC(Model View Controller) 패러다임의 방법을 자주 이용해 왔다. 웹 프레임워크도 이 개념을 이용하여, 웹 개발을 모델(데이터베이스)와 뷰(HTML, CSS)를 적절히 분리하고, 이를 적절히 연결하는데 주안을 두고 있다. 장고의 MVC개념도 유사한데, 약간은 다른 용어를 사용하고 있다.

  • 모델(Model) : 구조화되는 데이터. 객체와 관계 데이터베이스를 연결하여, ORM(Object-relational mapping)이라고도 한다.
  • 뷰(View) : URL 요청별로 데이터를 준비하는 역할을 한다.
  • 템플릿(Template) : 뷰에 준비된 데이터를 어떻게 보여줄 것인가에 대한 역할을 한다.

장고에서는 View가 Controller의 역할과 유사하고, Template이 View의 역할과 유사하다. 이렇게 용어를 사용한 이유는 뷰의 개념을 어떻게 보여줄지 보다는 어떤 데이터를 준비할 것인가에 대한 역할을 강조하였기 때문이다. 그래서 혹자는 장고의 MVC를 MTV(Model Template View) 라고 이야기하기도 하지만, 그다지 중요한 차이는 아니다.

여기서, 또 다른 파이썬의 웹 프레임워크 가운데 하나인 TurboGears와의 차이점을 볼 수 있는데, TurboGears는 각 요소별로 기존에 존재하는 파이썬 라이브러리를 이용하였고, 그것들을 조합한 반면, 장고는 각각을 직접 구현하였다. 장고 개발자들은 기존에 존재하던 도구들의 조합보다는, 빠른 웹사이트 제작을 위한 보다 더 최적화된 직접적인 구현을 선호하였던 셈이다.

장고의 중요한 특징 중 하나는 관리자 웹 인터페이스가 자동으로 제공된다는 것이다. 보통 웹 어플리케이션 작성에 있어서 관리자 인터페이스는 꼭 필요한 것이면서도, 일반적 기능과도 많이 중복되어, 구현이 번거롭던 것이 사실이다. 사용자관리, 사용자 그룹관리, 사용자 별 권한(permission)에 대한 것뿐 아니라, 각각의 모델 객체에 대해서, 목록/추가/삭제/변경의 기능이 관리자 인터페이스에서 모두 제공된다. 이는 특히, 데이터베이스, 웹 어플리케이션을 실험적으로 작성하기 좋다. 데이터베이스 모델링만으로(models.py 파일을 작성하는 것 만으로) 웹 어플리케이션의 작동을 실험해 볼 수 있다. 생물정보 관련 업무를 수행하는 필자 역시, 이 방법으로 데이터베이스화 해야 할 많은 정보들을 별다른 수고 없이 관리하고 있다.

그 밖의 장고의 특징으로, 세련된 URL 설계와 디자이너 친숙한 템플릿 기능을 들 수 있다. 가끔씩 게시판이나, 메신저등에서 보이는 하염없이 길기만 하거나, “?a=b&c=d” 등과 같은 깔끔하지 못한 URL은 장고로 만든 웹 어플리케이션에서는 찾아볼 수 없다. URL을 해석하는 부분에 정규식(Regular expression)을 사용하여, 개발자는 원하는 어떤 형태로도 URL을 설계할 수 있다. 구조화되고, 이해하기 쉬운 URL의 설계가 웹 어플리케이션의 전체적인 구조를 가늠하게 한다는 점을 생각해 볼 때, 이는 매우 반가운 기능이다. 템플릿 기능은 다른 웹 프레임워크들 역시, 가능한 한 쉽고, 빠르고, 웹디자인이 쉽도록 노력하고 있는데, 장고도 [XML]을 쓰지 않는다던가, 템플릿 태그를 확장 가능하도록 한다던가 등의 방법들을 통해, 이를 지원하고 있다. 얼마전 파이썬 창시자 귀도는 장고의 템플릿 기능이 타 프레임워크에 비해 더 세련되었다고 코멘트한 바 있다. (Django vs. Cheetah: 1-0) 그 외에도, 폭주하는 요청들을 처리해야 하는 대형 웹사이트들을 위한 최적화된 캐시(cache) 프레임워크를 제공하여, 메모리상의 캐시, 파일시스템 캐시, 데이터베이스 캐시 및 분산화 방법 등을 통해 고성능 요구 사항에도 최적화하였으며, 다국어지원 웹사이트를 위한 국제화([I18n], Internationalization) 지원도 충분하게 이루어지고 있다.

웹 요청이 들어왔을 때, 장고의 처리 절차는 아래 그림과 같다.

process.jpg

웹브라우저에 입력된, URL(request)을 URL resolver에서 해석하여, 적절한 뷰로 넘긴다. 뷰는 모델과 함께 데이터를 준비하고, 템플릿과 함께 어떻게 보여줄 지를 결정한 뒤에 웹 브라우저로 결과(response)를 보낸다. 파란색 부분은 미들웨어 역할의 콜백함수로서, 요청 결과(response)를 직접 조작한다. 이는 웹로봇 요청은 뷰까지 보내지 않도록 한다던가, 모델에서 중요한 정보는 결과로 내보내지 않도록 한다던가 등의 작업을 가능하게 한다.

블로그 만들기 예제

지금까지 장고의 특징들을 나열해 봤다. 이제, 직접 간단한 블로그를 만들어 봄으로써, 장고의 내부를 들여다 보도록 하자. django-admin.py 로 프로젝트를 하나 만들고, 그 안에 blog 어필리케이션을 만들자. 블로그는 저자가 글(포스트)를 쓸 수 있고, 방문자가 코멘트를 달 수 있다. 각 포스트는 태그(tag)를 갖는다.

데이터 모델링

블로그 어플리케이션의 모델은 크게 세가지, 포스트, 코멘트, 태그가 있다. 각각은 1:다, 다:다 관계를 갖는다. 글 하나에 여러개의 코멘트가 달릴 수 있고, 여러 개의 태그가 붙어 있을 수 있으며, 각 태그는 여러 개의 포스트에 등록될 수 있기 때문이다. 이를 models.py 에 기록하면 다음과 같다.

   1 from django.db import models
   2 
   3 class Post(models.Model):
   4     title = models.CharField(maxlength=200)
   5     content = models.TextField(maxlength=2000)
   6     ctime = models.DateTimeField(auto_now_add=True)
   7     mtime = models.DateTimeField(auto_now=True)
   8     is_public = models.BooleanField()
   9     tags = models.ManyToManyField('Tag')
  10 
  11 class Comment(models.Model):
  12     post = models.ForeignKey(Post)
  13     who = models.CharField(maxlength=30)
  14     content = models.TextField(maxlength=1000)
  15 
  16 class Tag(models.Model):
  17     name = models.CharField(maxlength=30)

필자는 예전에, 객체지향 프로그래밍을 익히면서, 객체를 관계형 데이터베이스 레코드와 어떻게 연결할 것인가를 가지고 많은 고민을 한 적이 있다. 다양한 시도들을 해봤으나 매끄럽지 않았는데, 장고의 모델 코드는 가장 파이썬답게 객체를 데이터베이스 레코드와 연결하고 있다. 사실 이것은 프레임워크를 쓰는 또 다른 이유이기도 하다. 직접 구현의 방법도 있지만, 경험 많은 개발자들의 검증되고, 안정된 방법들을 쓸 수 있는 것이다. 위 모델 코드로 포스트, 코멘트, 태그의 관계설정까지도 모두 자동으로 구현된다.

URL 설계

http://yourdomain.com/post/ ” 으로 모든 포스트 목록들을 보고, “/post/1” (포스트 아이디)로 특정 블로그의 내용을 보고 싶다. 그리고, “/admin/” 으로 관리자 페이지에 가고 싶다면, urls.py 를 다음처럼 작성한다.

   1 from django.conf.urls.defaults import *
   2 
   3 urlpatterns = patterns('',
   4     (r'^post/$','blog.views.post_list'),
   5     (r'^post/(?P<post_id>\d+)/$', 'blog.views.post_detail'),
   6     (r'^post/(?P<post_id>\d+)/comment/$', 'blog.views.add_comment'),
   7     (r'^admin/', include('django.contrib.admin.urls')),
   8     )

장고는 urlpatterns에 매칭되는 패턴이 없으면 HTML 404 페이지없음 오류 페이지를 출력한다. 각각의 URL 패턴들은 두 값을 가진 튜플들로 구성되어 있다. 앞엣것은 정규식 패턴이고, 뒤엣것은 해당 URL에 연결될 뷰이다. 정규식 패턴을 보면, 각각의 포스트를 보기 위해 패턴가운데, post_id가 숫자형태로 전달됨을 알 수 있다. include함수는 URL 정의를 하위 urls.py에 일임하고자 할 때 사용한다. 위에서 “/admin/” 이하의 모든 URL 패턴들은 장고에서 제공되는 admin.urls 에서 처리함을 알 수 있다. add_comment 뷰는 코멘트를 입력하는 부분에 사용된다.

뷰 만들기

위 URL 설계에 의하면, post_list와 post_detail, 두개의 뷰와 코멘트 입력을 담당할 add_comment 뷰가 필요하다. post_list는 목록을 보여주는 역할을 하고, post_detail은 특정 포스트를 보여주는 역할을 한다. 이들은 views.py에 다음처럼 작성된다.

   1 from django import forms
   2 from django.http import HttpResponseRedirect
   3 from django.shortcuts import render_to_response
   4 from blog.models import Post, Comment
   5 
   6 def post_list(request):
   7     return render_to_response('post_list.html', {
   8         'posts' : Post.objects.order_by('-ctime')[:5],
   9         })
  10 
  11 def post_detail(request, post_id):
  12     post = Post.objects.get(id=post_id)
  13     return render_to_response('post_detail.html', {
  14         'post' : post,
  15         'comments' : post.comment_set.all(),
  16         'comment_add_form' : forms.FormWrapper(Comment.AddManipulator(), {}, {}),
  17         })
  18 
  19 def add_comment(request, post_id):
  20     manipulator = Comment.AddManipulator()
  21     comment_data = request.POST.copy()
  22     comment_data['post'] = post_id
  23     manipulator.do_html2python(comment_data)
  24     manipulator.save(comment_data)
  25     return HttpResponseRedirect("../")

render_to_response 함수의 두 인수 가운데 앞엣것은 해당 뷰를 어떻게 보여줄 지에 해당하는 템플릿 파일을 지정하는 것이고, 두번째 인수는 그 템플릿에 전달할 컨텍스트(데이터)이다. “Post.objects.order_by('-ctime')[:5]” 는 Post 테이블에서 최근 5개의 목록을 가져오는 구문으로 SQL로 표현하면, “SELECT * FROM Post ORDER BY ctime DESC LIMIT 5” 와 같다. “[:5]” 부분만을 보고, SQL LIMIT구문을 쓰지 않고, 전체 리스트에서 슬라이싱하는 것이 아닐까 하고 생각할 수 있는데, 모델객체가 직접 __getitem__ 메서드를 오버라이드하여 LIMIT 구문을 삽입하는 역할을 한다. 또한 특정 Post에 연결된 코멘트들은 comment_set 속성으로 접근 가능하다. 코멘트 입력을 받기 위해 폼 데이터 또한 준비해야 하는데, 장고의 AddManipulator는 모델 입력 용 폼을 위한 처리자로서, 입력데이터가 올바른지 검증하는 역할까지 자동으로 수행한다.

템플릿 만들기

포스트들의 목록을 출력하는 템플릿 post_list.html 은 다음처럼 작성된다.

<h1>최근 5개 글 목록</h1>
<ul>
{% for post in posts %}
    <li><a href=”{{ post.id }}”>{{ post.ctime }} | {{ post.title }}</li>
{% endfor %}
</ul>

{% %} 는 장고 템플릿에서 태그라고 말하는 것으로서, for, if, ifequal 등의 제어구문을 이용할 수 있다.  {{ }}  안에는 View에서 넘겨준 변수를 적어주며, “.” 이후에 해당 변수의 속성을 적어준다. 포스트의 상세목록을 표시하는 템플릿 post_detail.html은 다음처럼 작성한다.

<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>

<h3>태그</h3>
<p>
{% for tag in tags %}
    {{ tag.name }}</a>
{% endfor %}
</p>

<h3>코멘트</h3>
<ul>
{% for comment in comments %}
    <li>{{ comment.content }} -- {{ comment.who }}</li>
{% endfor %}
</ul>
<form method="post" action="comment/">
    <p><label for="id_who">이름 : {{ comment_add_form.who }}</p>
    <p><label for="id_content"> {{ comment_add_form.content }}</p>
    <p><input type="submit" value="코멘트입력"></p>
</form>

폼 부분을 보면, 어떤 input 타입을 쓸지가 지정되지 않았는데, 이는 모델에서의 속성에 맞게 자동으로 만들어 진다.

동작 확인

위 코드만으로 블로그의 기능이 다 만들어졌다. 글 쓰는 기능은 안 만들었다고? 아하, 글을 쓸 때는 장고의 관리자 모드를 이용하면 되겠다. URL “/admin/” 으로 접속하면 그림 2의 화면을 볼 수 있다. 웹 어플리케이션에서 자주 이용되는 User, Group 에 대한 기능들은 이미 만들어져 있음을 볼 수 있다. 지금까지 설계한 블로그 모델도 입력할 수 있는데, 그를 위해서는 각 모델에 “class Admin: pass” 라는 속성을 추가하면 된다.

admin1.jpg

admin2.jpg

깔끔한 인터페이스의 관리자 화면. 사용자, 사용자 그룹 및 작성한 모델들의 목록/생성/수정/삭제 가 모두 가능하다.

자, 이제 관리자 인터페이스에서 글을 쓰면 된다. URL “/post/” 로 가면, 최근 글 목록 5개가, 그리고 “/post/post_id” 로 가면 포스트내용이 표시되고, 코멘트도 입력 가능한 블로그 웹 어플리케이션이 완성되었다.

맺음말

지금까지 별 다른 수고 없이 깔끔하게 데이터베이스기반의 웹 어플리케이션을 만들어 봤다. 이런 방법으로 웹사이트를 만드는 것은 직접적인 CGI 프로그래밍의 방법보다 훨씬 더 그럴 듯 하고, 안정적이고, 쉽고 빠르다. 여기서 빠르다는 것은 시사하는 바가 큰데, 개발시간이 0에 가까워 질수록 인터넷 세상은 어떻게 변할 것 같은가? 라는 최근의 IT 업계의 질문을 잘 생각해보면 느껴지는 바가 많을 것이다. 장고를 비롯한 최근의 웹 프레임워크들은 이러한 현실을 앞서서 만들어가고 있다.

장고는 해외에서 각종 온라인 신문사를 비롯, 다양하게 활용되고 있으나, 국내에서는 그다지 많이 활용되지 않는 듯 하다. 필자가 직접 관여했던 프로젝트들을 소개하면 다음과 같다.

  • GAVI : Genome Ajax Viewer ( http://insilicogen.com/dj/gavi ) : 유전체(genome) 탐색기. 사용자가 직접 유전체학 실험결과를 가지고, 지도를 그리고, 추가 정보를 관리할 수 있다.

  • GMP Study ( http://gmp.biohackers.net/ ) : 굿모닝팝스 뉴스받아쓰기 사이트. 이 사이트의 개발과정이 2006 대안언어축제에 소개되었다. 각 단계별로 어떻게 만들었는가를 확인할 수 있다. ( EnglishStudyWithDjango )

참고자료

  1. 장고 홈페이지

  2. ThePragmaticProgrammer: from journeyman to master (Andrew Hunt, David Tomas, 020161622X )

  3. Python WebServerGatewayInterface v1.0

  4. TurboGears 홈페이지

  5. 귀도의 웹 프레임워크 템플릿 관련 코멘트, Django vs. Cheetah: 1-0


CategoryArticle

Bhn: RapidWebDevelopmentByDjango (last edited 2011-09-14 15:55:56 by yong27)

web biohackers.net