2005/11/28

결혼이 부러울 필요는 없다.

많은 사람들이 결혼을 하는 사람들을 보면 부러워 한다.
뭐 내 경우엔 너무 많은 결혼식을 이곳저곳에서 보아온 탓에
때때로 가슴 시린 경우도 있고 아무렇지 않은 경우도 종종 있다.

지난 일요일 친구 결혼식에 오랜만에 본 고교 여자 동기를 집근처까지
데려다 주었다.(물론 이 여자동기는 거나하게 술에 취해있었다)

가는길에 몇마디를 주고받았는데, 내가 했던 말중 기억하는건 다음의 말이다

"결혼하는 사람들은 그 사람들이 할 새로운 일을 찾은 거고 그렇지 않은 사람들은
결혼한 사람들이 못하는 일을 할 수 있어. 그리고 할 수 있잖아. 아직 우린 젊으니까"

젊음의 상징을 땅끝으로 내려버리는게 설렁 결혼이라 하더라도 어디까지나 새로운
인생의 시작이라고 생각한다.

많은 선남선녀들이여. 결혼한 부부나 애정이 지나치게 과다한 커플들을 보며 부러워
하지 마라. 그대들에게도 그에 버금가는 일들이 존재할 것이다!!!

법도

술을 먹는것도 법도가 있는 법이다.

나를 지킬줄 알 정도로 먹는 건 술을 먹는 사람이 가져야 할 덕목이다.
이 시대의 청춘들이라면 나를 지킬 줄 알 정도까지만 먹어라!!!

고교 여자 동기의 결혼식에 참석해서..

지난 일요일에 친구가 결혼을 했답니다.

애(?)는 이미 있는 상태에서 한건데.. 이쁘더군요..

치장한 탓인가???

결혼식에 간 목적 자체가 축복 and 결혼진행을 위한 사회자로
간거였습니다.

아침부터 부산하게 여자동기 한녀석 태워서 영동으로 내달렸습니다.
(사실 요즘에 돈이 없어서 고속도로를 타지 않는 탓에..;;)

어찌하였든.. 국도로 달려서 도착후에 봉투 축의금 넣고
수염(?) 그나마 있던것도 정리하고, 신부보고... 사회를 진행하러
갔지요.

근데 사회 볼때 실수 안할까 무지 걱정했는데 예상대로 빙고~
순서를 하나 빼먹는 바람에 무지 난감했더라지요.

어쨌든 식이 끝나고.. 피로연에서 또 이런저런 얘기 하다가
저녁때즘.. 큰 집에 가서 책좀 가지고 오고 도서관가서 1시간 정도
낮잠 자다가(안자면 운전할때 졸려서 위험하다는..) 6시 쯤 밥먹는다고 해서
또 갔죠. 그게 뭐하는 짓이었는지..

가서 이 사람 저 사람 막 이야기하다가 왠지 얼굴이 낯익은 사람이 보이더군요
결혼한 친구에게 물어봤죠.. 너 결혼식에 "박민희" 왔냐고 물어봤더니만 아니나.
다를까요. 예상대로 그 사람이더군요.. 고교 2년때 잠깐 감정을 비쳤던 사람
이긴 했는데 예전보다 이뻐졌다고 해야 되나요? 사람들이 나이를 먹으니
이전에 볼 수 없던 또 새로운 모습을 보게 되네요.

6시에 처음 모여서는 고기집 가서 신나게 고기를 먹어주고 술을 권하는 걸 억지로 피하고, 2차로는 노래방 가서 즐기는 도중에 몇 사람들(제 친구 둘을 포함해서 민희라는 친구까지)와 그외 1사람은 자리를 떴습니다(늦게 가면 안 좋잖아요^^)

그리고 저는 3차인 호프집까지 가서 신나게 술은 먹지 못하고(서울까지 운전해야 했으니까요) 얘기하고 그랬죠. 가서 다리 잘 못 꼬다 앞에 있는 신부의 친구중 한 사람 다리를 슬쩍 차버렸는데 그대로 모른척 하다가 앞에 있는 여자분이 "아까 제 다리 찼죠? 미안하죠? 그럼 술 드시죠?"라고 해서 허걱 소리를 내면서 다음에 마시겠다고 했지요.. 아마 바로 전에도 생일월을 말하니 연장자(?)라면서 술을 먹이려 해서 억지로 피했다는..

그 자리에 군대간 고교 후배도 참석해서 술을 마셨는데 그녀석은 이미 거나하게
취해있었고 신부 친구들과 신랑 친구들도 이미 정신을 차릴 수 없는 상태까지 간듯 했습니다.

마지막 나오면서 아까 슬쩍 다리를 쳤던 여자분에게는 다음에 만나면 맘껏 마셔주겠다고 하고 약조를 했습니다(이런거 그냥 넘어가면 다음에 목숨(?)이 위태롭죠)

아울러 같이 있던 신부의 남자 동기에게도...

그리고 저는 술에 거나하게 취했던 고교 여자동기를 부축해서 차에 태우고 집앞
까지 데려다 주고 열나 먼 국도를 통해 서울로 돌와왔습니다.

뭐 진짜 문제는 차에서 안 내리고 자는 바람에 회사에 또 지각했다는 것이지요.
아우~~~
정말 어제 하루동안만 해도 아침부터 오늘 새벽까지 정말 죽을 맛 이었습니다.

술의 유혹도 참고.. 그랬는데.. 흐음...

다음에 만나면 정말 약조한 것은 꼭 지켜서 뒤탈이 없게 해야 된다는 생각이 듭니다.

참.. 결혼식 진행하고 신랑신부 보면서 느낀 게 하나 있습니다

"사랑은 생각으로 하는게 아니고 마음으로 하는 거라고 그리고 그 마음은 사람의 눈빛을 통해서 전달된다고요"

결혼식 도중에 신랑신부를 골탕먹인게 가장 하이라이트군요.
"신랑 정유식 군은 죽을때까지 염명호양을 사랑하겠다고 예식장이 떠나갈때까지 3번을 외쳐주시기 바랍니다"
"신부 염명호양은 신랑이 옆에 있으니까 좋죠? 신랑 만세를 3번 외쳐주시기 바랍니다"

^^...

참 저는 신랑이 아니고 신부 친구였습니다(신부 친구가 사회보는 기이한..)

2005/11/24

달팽이관의 괴로움..

요즘들어 몸이 피곤한데..

달팽이관을 괴롭히고 있다.(이러다 더 안 좋아지고 있음)
어찌하였거나.. 에헤라 데라. 어딜가냐.. 나두 데려가라~

2005/11/22

Spyce와 함께 하는 파이썬 웹 프로그래밍 3

Spyce와 함께 하는 파이썬 웹 프로그래밍 3


Spyce와 Cheetah 템플릿 프로그래밍


이번호에서는 웹 프로그래머와 웹 디자이너 간에 싸우지 않는 범위를 제공하는 특별한 유틸리티인 Cheetah 템플릿을 Spyce에서 사용하는 방법과 2편에서 배웠던 데이터베이스 사용을 Cheetah 템플릿을 통해 구현해보기로 한다.


이상호 search5@gmail.com


현재 리눅스 엔지니어로 일하고 있으며, 웹과 그 기반 기술들에 대해 관심이 많다. 파이썬과 PostgreSQL에도 관심이 많아 항상 이 둘을 어떻게 하면 잘 사용할까 생각한다. 요즘은 동갑내기 여자 가수인 이소은을 쫓아다니며 어떻게 하면 고백할 수 있을까 고민 중이다.


연재순서


1회 2005.10 Spyce를 통한 PSP 프로그래밍

2회 2005.11 Spyce와 데이터베이스 연동

3회 2005.12 Spyce와 Cheetah를 이용한 템플릿 사용


웹 프로그래머는 웹 프로그램을 설계하고 제작하는 동안에 디자이너와 싸우는 일이 일상에 포함되어 있다고 말할정도로 사이가 좋지 않다. 서로간의 의사소통이 잘 되지 않는 것이 그 첫 번째 이유가 되겠지만 다른 이유도 있다. 서로간의 일의 영역을 직접적으로 침범하는 것이 그 2번째 이유가 있다.


예전과는 세태가 많이 변한 지금은 영역 침범에 있어 그다지 깊게 침범하지 않게 되었는데 이러한 것의 주요한 변화의 중심에는 템플릿이 존재한다. 그렇다면 템플릿은 무엇이고 왜 사용하는가를 먼저 알아보도록 한다.


템플릿은 영한사전에서 다음과 같은 뜻을 가지고 있다.

① 어떤 도식이나 서식에서 자주 사용되는 기본 골격. 스프레드시트에서 각종 데이터 처리를 위해 표의 일정한 구조를 만들어 놓고 사용자가 데이터를 입력만 하면 되도록 해 놓은 것이 한 예이다.

② 그래픽 프로그램에서 자주 사용하기 위해 미리 정해 놓은 그림이나 이미지의 일정한 패턴


꺼내서 이야기 하고자 하는 주제는 1번의 뜻이다. 웹에서 템플릿의 사용은 프로그램과 디자인의 분리에 그 이유가 있다. 템플릿은 현재 프로그래밍에 쓰이는 언어와 상관없이 웹 프로그래밍을 하는 곳이라면 사용되어 지고 있다.


그렇다면 웹에서의 템플릿은 어떻게 사용되어지고 있을까? 웹에서의 템플릿 사용은 사용자에게 보여지는 페이지. 다시 말해 순수한 HTML 페이지안에 프로그램에서 출력하는 값을 출력하기 위해 특정한 코드를 넣는 방법으로 템플릿은 사용된다.


파이썬에서는 많은 템플릿 언어가 있다. 지금 이야기하고자 하는 Cheetah 템플릿 외에도 Empy, SimpleTAL 등이 있는데 여기서는 이전 2편에서 예고한대로 Cheetah 템플릿을 Python에서 사용하는 것을 다룬다.


Cheetah 템플릿은 Python 기반의 템플릿 언어이다. Cheetah 템플릿은 배우기 쉬운 언어중 하나이다. Cheetah 템플릿은 다음의 사이트에서 얻을 수 있다.


(cheetah-homepage.png)

[그림 1] Cheetah 템플릿 사이트(http://www.cheetahtemplate.org/)


Cheetah 템플릿 설치

이제 Cheetah 템플릿을 사용하기 위해서 Cheetah 템플릿을 설치하고 사용해보자. 우선 할 것은 Cheetah 템플릿 홈페이지에 방문하고 Cheetah 템플릿을 설치하는 것이다.


Cheetah 템플릿을 다운로드 받기 위해 Download 링크로 가면 SourceForgeproject page 라는 링크를 볼 수 있다. 이 링크를 눌러 Sourceforge.net의 프로젝트 사이트로 이동한다. 그럼 화면 중간에 Latest File Releases 라는 섹션이 있고 바로 아래 Cheetah 라는 낯 익은 이름과 옆쪽으로 현재 버전인 1.0rc2 가 명시되어 있고 그 옆에 Download 라는 링크를 클릭하면 Cheetah 템플릿을 다운로드 받을 수 있다. 제공되는 형식은 tar.gz 형식이다.


http://sourceforge.net/project/showfiles.php?group_id=28961&package_id=20864&release_id=372298


Cheetah 템플릿의 설치는 Linux에서 다음과 같은 절차를 따라 설치한다.

* Cheetah 템플릿을 다운로드 받는다.

* gzip으로 압축된 tarball 형식의 압축을 임의의 디렉토리에 풀어낸다.

* 루트 유저로 계정을 변경한다.

* 임의의 디렉토리에서 다음의 명령을 내린다.: python setup.py install

* 다음의 디렉토리로 이동한다.: /usr/lib/python2.3/site-packages/

* 다음 명령을 내린다: chmod -R a+r Cheetah*

* 다음 명령을 내린다: chmod a+x `find Cheetah -type d`


Cheetah 템플릿을 설치하기 위해선 python-dev 패키지가 필요하다. 파이썬 버전에 따라 site-packages 디렉토리의 위치는 조금씩 다를 수 있다. 필자의 경우는 파이썬 버전은 2.3에서 하였다.


이제 Cheetah 템플릿 설치를 마쳤으니 본격적으로 Cheetah 템플릿에 대해 알아보고 Spyce에서 어떻게 Cheetah 템플릿을 사용해서 PSP 페이지를 만들어내는지 보자.

Cheetah 템플릿 언어 구성

Cheetah 템플릿은 크게 11개 부분으로 표 1과 같이 구성되어 있다.

요약 이름

포함되는 내용

주석

(a) ## single line

(b) #* multi line *#

Generation, caching and

filtering of output

(a) plain text

(b) lookup a value : $placeholder

(c) evaluate an expression : #echo ...

(d) same but discard the output: #silent

(e) one-line if: #if EXPR then EXPR else EXPR

(f) gobble the EOL : #slurp

(g) parsed file includes : #include

(h) raw file includes : #include raw

(i) verbatim output of Cheetah code: $raw .. #end raw

(j) cached placeholders: $*var, $**var

(k) cached regions: #cache ... #end cache

(l) set the output filter: #filter

(m) control output indentation: #indent

파이썬 모듈 임포트

#import ..., #from ...

상속

(a) set the base class to inherit from: #extends

(b) set the name of the main method to implements ...

컴파일 시간에 정의

(a) define class attributes: #attr

(b) define class method: #def ... #end def

실행시간에 할당

(a) local vars: #set

(b) global vars: #set global

(c) deleting local vars: #del

순서 제어

(a) #if ... #else ... #else if(aka #elif) ... #end if

(b) #unless ... #end unless

(c) #for ... #end for

(d) #repeat ... #end repeat

(e) #while ... #end while

(f) #break

(g) #continue

(h) #pass

(i) #stop

에러/예외 핸들링

(a) #assert

(b) #raise

(c) #try ... #except ... #else ... #end try

(d) #try ... #finally ... #end try

(e) #errorCatcher ...set a handler for exceptions raised by $placeholder calls.

파서/컴파일러 명령어

(a) #braekpoint

(b) #compiler-settings

파이썬 코드 이스케이프

(a) evaluate expression and print the output: <%= ... %>

(b) execute code and discard output: <% ... %>

Cheetah로부터 생성된

파이썬 모듈 제어

(a) set the source code encoding of compiled template modules: #encoding

(b) set the sh-bang line of compiled template modules: #shBang

<표1> Cheetah 템플릿 언어 구성


11개 부분은 또 다시 몇 개의 세세한 부분으로 나뉘어진다. 표1에서는 필자가 글을 쓰면서 혹시 오역한 부분이 있을까 하여 원문 설명을 기재하였다. 이제 서서히 11개 부분의 구성 요소에 대해 알아보며 사용방법을 익혀보기로 한다.


1. 주석

주석은 어떤 프로그래밍 언어든 매우 중요한 요소로 군림되어 온다. 요약해서 주석 없는 프로그램은 쓰레기일 뿐이다. 물론 오래전이야 주석은 없거나 말거나 크게 신경 쓸 요소는 아니었다지만, 소프트웨어 개발비용의 80% 이상을 가져가는 요소가 유지보수라고 하니 유지 보수에 필요한 주석은 몇 번을 말해도 크게 어긋나지 요소가 아닐 수 없을 것이다.


하지만 이러한 주석의 사용에는 무조건 많이 다는 것보다 적재적소에 배치하는 것이 주석을 사용하는 올바른 방법이다. Cheetah에서도 주석을 사용할 수 있는데 크게 2가지의 사용방법을 가지고 있다.


싱글 라인 주석 : ## single line

멀티 라인 주석 : #* multi line *#


코드1은 주석의 간단한 사용방법을 보여주고 있다.


## Cheetah 의 한 라인 주석입니다.

#*

여기에는 여러줄의 주석을 만들 수 있습니다.

주석이 길면 여기에 넣으면 되겠지요?

*#

[코드1]


2. Generation, caching and filtering of output

템플릿의 사전적 의미를 기억한다면 템플릿은 단지 틀이라는 것이 기억날 것이다. 그렇다면 틀에 데이터를 어떻게 넣을 수 있는가에 대한 질문은 프로그램에서 템플릿으로 데이터를 내보내는 것으로 답을 나타낸다. 물론 이 부분에서는 단순한 출력 이외에 다양한 출력 요소가 포함되어 있다. 다음에 나열할 요소는 실제 활용되고 있는 주요한 요소들이다.


(a) 일반 텍스트

(b) 값 찾기 : $placeholder

(c) 수식 계산 : #echo ...

(d) 수식이 실행된 결과를 출력하지 않는다 : #silent ...

(e) 1라인 조건문 : #if ... then ... else ...

(f) gobble the EOL : #slurp

(g) 파일 인클루트 : #include ...

(h) 변수 캐쉬 : $var, $**var

(i) 영역 캐쉬 : #cache ... #end cache


(a) 일반 텍스트

일반적인 텍스트를 출력하며 별도로 텍스트를 감싸거나 하는 것은 없다. 일반적인 텍스트를 써주면 출력된다.

(b) 값 찾기 : $placeholder

스크립트에서 보내온 값을 찾아 출력한다. 별도로 $placeholder라는 변수나 제어문은 아니다. 값 찾기는 다양한 방법으로 찾을 수 있는데 권장되는 방법은 중괄호({ }) 로 둘러싸인 형식이다.

${var}

${var['abc']}


참고박스 - $placeholder 란?

본문에서 $placeholder 란 이름을 자주 쓰게 될 텐데 Cheetah 템플릿에서 변수를 지정하는 별도의 룰의 이름이다. 실제 이 이름은 쓰이지 않으므로 여기서는 변수를 이름짓는 룰이라고 생각하자.


한가지 주의할 것은 값을 찾을 때 변수명은 대소문자를 구별한다는 것이다. 다음의 예를 보면 이해가 쉬울 것이다.

(O) ${var} (X) ${Var} (X) ${vAR} (X) ${vaR}


(c) 수식 계산

지시어명 : #echo

문법 : #echo EXPR

수식을 계산해 출력한다. 수식 값을 바로 출력할 필요가 있을 때 유용하게 사용할 수 있다. 물론 이러한 수식 계산은 템플릿 안에서 수행되고 이러한 수식이 캐싱될 경우 서버로 가해지는 부담이 덜어질 수 있다. 다음은 수식의 사용 예와 그림2의 출력결과를 보여준다. 예제는 예제1에서 (c), (d), (e) 의 spy 스크립트 파일과 템플릿 파일을 보여준다.


예) Here is my #echo ', '.join(['silly'])*5) #example


(d) 수식이 실행된 결과를 출력하지 않는다

지시어명 : #silent

문법 : #silent EXPR

#echo 와 다르게 수식이 실행된 결과를 출력하지 않는다. 이 지시어는 수식이 필요한데 계속 출력될 경우에 수식값을 출력하지 않음으로서 나중에 수식을 재이용할 수 있도록 한다. 그림2는 #slient의 출력 결과를 보여주지 않는다.


(e) 1라인 조건문

지시어명 : #if ... then ... else ...#

문법 : #if EXPR1 then EXPR2 else EXPR3#

1라인 조건문은 즉석에서 바로 조건에 따라 결정해야 할 경우 사용할 수 있다. 1라인 조건문은 c나 PHP에서 다음과 같은 문장과 같은 기능을 수행한다. 그림2는 #silent의 출력 결과를 보여주지 않는다.

(EXPR1) ? EXPR2 : EXPR3


--- (echo_not_if.spy) ---

[[.import name=template]]


[[=template.cheetah('echo_not_if.tmpl')]]

--- (ehco_not_if.tmpl) ---

## echo directive execute

Here is my #echo ', '.join (['silly'])*5 # example


## slient directive execute

#silent 1+2


## 1line if directive execute

#if (1+2) == 4 then 3+4 else "values not equal 3"#

<예제1> #echo, #silent, 1라인 #if 지시어 사용 예제


(equal_not_if.png)

<그림2> #echo, #silent, 1라인 #if 지시어 출력


(f) gobble the EOL

지시어명 : #slurp

문법 : #slurp

Python은 값을 출력한 이후 자동적으로 개행을 한다. 이러한 개행을 억지로 막기 위해서 #slurp 지시어를 사용한다. #slurp 지시어는 개행을 처리하는 문장뒤에 붙을 수 있다. #slurp 지시어는 #if, #for, #while 등의 개행을 자동적으로 처리하는 지시어 등에서 사용된다.


(g) 파일 인클루드

지시어명 : #include

문법 : #include FILENAME_EXPR

Cheetah 템플릿에서는 직접적으로 파일을 인클루드 할 수 있다. 물론 spyce 내에서도 include 문을 사용해서 파일을 인클루드 할 수 있다. 그렇지만 템플릿 내에서 인클루드 하는 것은 조금 더 특별한 의미를 지닐 수 있다. 예를 들어 head.html 파일을 인클루드 하는데 이 것을 모든 페이지에서 스크립트 파일이 제어한다면 디자이너는 항상 스크립트 파일을 수정하거나 프로그래머에게 맡겨야 하지만 바로 필요한 파일을 직접 인클루드 할 수 있다면 마찰도 조금 더 적게 일어날 수 있을 것이다.


#include 지시어는 크게 2가지 문법이 있다. 코드2는 그 문법을 보여준다. 그림3과 예제2는

인클루드의 사용 예를 보여준다.


#include "includeFileName.txt"

#include source=$myParseText

<코드2> 인클루드 예


--- (include.spy) ---

[[.import name=template]]


[[

myParseText="/var/www/apache2-default/included_file.txt"

]]


[[=template.cheetah('include.tmpl')]]

--- (include.tmpl) ---

## included_file.txt including

#include "/var/www/apache2-default/included_file.txt"


## include source attribute including

#include source=$myParseText

##include source="/var/www/apache2-default/included_file.txt"

--- (included_file.txt) ---

인클루드 되는 파일입니다. 이 파일은 2번 인클루드 될 것입니다

<예제2> 인클루드 실행 예제


(include_executing.png)

<그림3> 인클루드 실행 예제


참고박스 - #include 지시어 사용시 경로사용에 대해서

앞서 예제에는 크게 2가지 문법으로 파일을 읽어들인다고 했는데, 인클루드의 경로를 자세히 보면 알 수 있겠지만 2가지 문법으로 파일을 인클루드할 때 반드시 시스템(웹이 아님)의 / 를 기준으로 절대 경로를 써주어야 한다.


(h) 변수 캐쉬

문법 : $var, $**var

변수 캐쉬는 어떤 변수를 캐싱할 필요가 있을 때 유용하게 사용할 수 있는데 크게 3가지의 사용용법이 존재한다.

표2는 변수를 캐쉬하는 방법을 보여준다.

변수 사용

영향

$var, ${var}

dynamic - 요청할때마다 변수를 갱신한다.

$var, $*{var}

static - 변수는 캐싱되서 변하지 않는다.

$*5*var, $*5*{var}

timed refresh - interval이 지나면 요청했을 때 값을 갱신한다.

<표2> 변수 캐쉬 사용방법 예


interval을 사용한 방법에서 주의할 점은 interval은 초를 의미한다.


(i) 캐쉬 영역

지시어 : #cache ... #end cache

문법 :

지시어명

문법

#cache

#cache [id=EXPR] [timer=EXPR] [test=EXPR]

EXPR

#end cache

<표3> 캐쉬 영역에 사용되는 문법


Cheetah에서는 변수 값뿐만 아니라 일정 영역을 캐쉬 영역으로 지정해서 캐싱이 가능하다. 캐쉬 영역에서는 변수 캐시 방법을 사용할 수 있으며, 캐시가 지속될 시간을 지정할 수 있다.


3. 파이썬 모듈 임포트

지시어명 : #import, #from

문법 :

지시어명

문법

#import

#import moduleName

#from

#from moduleName import (methodName or ClassName)

<표4> 파이썬 모듈 임포트 문법


Cheetah에선 #import 지시어와 #from 지시어를 사용해서 파이썬 모듈들을 임포트해서 사용할 수 있는데 본래의 템플릿 사용 용도를 위해하니 권장하지 않는다.


예) #import math

#from math import sin, cos


4. 상속

지시어명 : #extends

문법 : #extends className

템플릿 페이지 내에서 #extends 지시어를 사용하면 템플릿 페이지는 서브 클래스가 되어 페이지를 만들 수 있다. 이 외에 #implements 지시어가 있다.


5. 컴파일 시간에 정의

지시어명 : #attr, #def

문법명 :

지시어명

문법

#atrr

#attr $placeholder=값

#def

##def METHOD[ (ARGUMENTS) ]

...

#end def

// 이 문법은 여러줄의 메소드를 정의하기에 좋다.

#def METHOD[ (ARGUMENTS) ] : TEXT_AND_PLACEHOLDERS

// 이 문법은 1 라인으로 이루어진 메소드를 정의하는데 사용된다.

<표5> 컴파일 시간에 정의하는 지시어 문법


Cheetah 템플릿을 컴파일 할 때 2가지의 지시어를 사용해서 템플릿 프로그래밍을 더욱 유용하게 할 수 있는데, 다음의 2가지는 템플릿 자체에 유용하기 보다 템플릿 자체적으로 사용하기 위해서 유용한 것이다.


#attr : 클래스 내의 속성을 정의한다.

#def : 클래스 내의 메소드를 정의한다.


1번째 문법은 파이썬에서 너무나 자주 사용하는 문법이지만 2번째 문법은 흡사 람다식을 연상케 한다.


이렇게 정의된 메소드는 $METHOD() 형식으로 호출한다. 예제3과 그림4는 attr 지시어와 #def 지시어의 사용을 실례로 보여준다. 메소드는 소괄호를 명시하지 않아도 호출이 가능하다.


--- (attr_def.spy) ---

[[.import name=template]]



[[\

a = "a"

b = "b"


def c(number):

return number

]]


[[=template.cheetah('attr_def.tmpl')]]

--- (attr_def.tmpl) ---

## attr directive usage

#attr $title = "Rob Roy"

#attr $author = "Sir Walter Scott"

#attr $version = 123.4


$title, by $author, version $version


## def directive usage

#def myMeth()

This is the text in my method

$a $b $c(123) ## these placeholder names have been defined elsewhere

#end def


## and now use it...

$myMeth()


## 1 line def directive usage

#attr $adj = 'Travel'

#def myMeth2: This is the $adj method

$myMeth2

<예제3> #attr 지시어와 #def 지시어 예제


(attr_def.png)

<그림4> #attr 지시어와 #def 지시어를 사용한 것을 출력


6. 실행 시간에 할당

지시어명 : #set, #del

문법 :

지시어명

문법

#set

#set $adj = 100

// adj 란 이름의 지역변수 선언

#set global $adj

// adj 란 이름의 전역변수 선언, 지역변수가 선언되어 있으면 지역변수가 우선한다.

#del

#del 변수명

// 변수를 삭제하며 삭제할 수 있는 변수 범위는 지역변수만 삭제할 수 있다.

<표6> 실행시간에 사용할 수 있는 지시어의 문법


실행 시간에 값을 할당하는 것은 혹시나 모를 상황에 대비해서 값이 스크립트에 없을 경우 임의의 값으로 처리하기 위해서이다. 값의 선언은 2개방법이 있지만 값의 삭제는 1개방법만 있다. 흔히 지역 안에서 선언되는 값을 지역변수라고 한다.


#set $adj = 100 ## 지역변수 선언

#set global $adj = 100 ## 전역변수 선언


물론 이 값을 삭제하기 위해선 #del 지시어를 사용할 수 있다. 그렇지만 여기서 주의할 것은 #del 지시어는 지역변수 값만 삭제한다는 사실이다. 값의 삭제는 한번에 여러개의 값이 삭제가 가능하다. 다음은 그 방법을 보여주고 있다.


#del $adj, $ss501


7. 순서 제어

템플릿이 단지 틀만 제공하는 것이라 하지만 스크립트에서 미처 처리하기 어려운 것은 템플릿에서 프로그래밍을 처리가 가능하다. 앞서 컴파일과 실행시간에 정의하고 할당하는 것은 미처 처리하기 어려운 것을 처리하기 위해 효과적이다. 하지만 여기서 순서 제어는 단지 처리하기 어려운 것만을 처리하기 위해서만은 아니다. 이러한 예를 가장 잘 뒷받침 해주는 것은 테이블인데, 테이블에는 서로 다른 데이터가 같은 열(column)을 유지하며 새로운 행(row)를 출력하는데, 이러한 데이터를 출력하기 위해선 반복이 필수적이다. 다음은 이러한 제어를 하는데 필요한 몇 가지 주요한 지시어를 설명한다.


지시어명 : #for ... #end for

문법 :

지시어명

문법

#for

#for $placeholder in EXPR

EXPR

#end for

<표7> #for 지시어 문법


지시어명 : #if .. #end if

문법 :

지시어명

문법

#if

#if EXPR

...

#else if EXPR

...

#elif EXPR

...

#else

...

#end if

<표8> #if 지시어 문법


#if 지시어의 주 사용 용도는 너무도 자명한데, 다시한번 설명을 들어보면 어떤 표현식이나 $placeholder 에 따라 서로 다른 표현식 또는 $placeholder를 출력한다. #if 지시어는 #else if 지시어와 #elif 지시어 와 동등한 순위를 갖게 되는데 #else if 지시어는 #elif 지시어는 서로 같은 의미이다. 사용할 경우 어떤 것을 사용한다고 먼저 명시해두고 사용하는게 좋다.


지시어명 : #break, #continue

문법 :

지시어명

문법

#break

#break

#continue

#continue

<표9> #break, #continue 지시어 문법


#break 지시어는 for 지시어에서 사용 가능하며 #continue 지시어는 while 지시어에서 사이 가능하다


지시어명 : #stop

문법 : #stop

템플릿 수행을 정지한다. 이때의 템플릿 컴파일 수행은 잠시 정지되는 것이 아니라 템플릿 컴파일을 멈추어 버린다.


8. 에러/예외 핸들링

파이썬에서만 에러와 예외 처리가 가능한 것은 아니다. 템플릿 내에서도 예외와 에러 처리가 가능한데 다음의 방법과 문법으로 에러와 예외 처리가 가능하다.

지시어명

문법

#try

#try

...

#except [ErrorClass]

...

#end try

#try

..

#except [ErrorClass]

...

#else

...

#end try

#try

...

#flnally

...

#end try

<표10> 예외/에러 핸들링 문법


ErrorClass는 파이썬의 에러 클래스를 사용한다. 에러 클래스에 대해 알고 싶으면 파이썬 에러 클래스를 찾아보시길 바란다.


위와 같은 수동적인 방법으로 에러 처리를 외에도 #errorCatcher 지시어와 ErrorCatcher 객체를 이용해서 에러를 자동적으로 처리할 수 있는 방법도 존재한다.


9. 파서/컴파일러 명령어

지금까지 지나왔던 내용이 단지 템플릿을 구성했다면 지금 알아볼 것은 템플릿을 디버깅하고 제어하는 부분이다.

지시명 : #breakpoint

문법 : #breakpoint

#breakpoint 지시어는 #stop지시어와 기능상 거의 동일하지만 사용 위치가 다르다. #stop은 제어 지시어인 #if 등에 상관없이 아무곳에서나 동작하지만 #breakpoint 지시어는 제어 지시어의 위치에 삽입되어 동작한다. 조금 복잡하게 설명한 감이 있지 않나 싶은데 #stop은 템플릿의 실행을 완전히 정지하는 것이고 #breakpoint 지시어는 템플릿 실행중에 디버깅할 때 사용하는 지시어라는 차이점이 존재한다.


지시어 : #compiler-settings

문법 :

지시어명

문법

#compiler-settings

#compiler-settings

...

#end compiler-settings

<표11> compilert-settings 문법


#compiler-settings 지시어는 템플릿 컴파일 환경을 지정할 수 있다. 지정할 수 있는 것은 문법과 코드 생성에 관해서 컴파일러 설정이다.

syntax settings

code generation settings

(a) cheetahVarStartToken

(b) commentStartToken

(c) multilineCommentStartToken

(d) multilineCommentEndToken

(e) directiveStartToken

(f) directiveEndToken

(a) commentOffset

(b) outputRowColComments

(c) defDocStrMsg

(d) useNameMapper

(e) useAutocalling

(f) reprShortStrConstants

(g) reprNewlineThreshold

<표12> compiler-settings에서 사용 가능한 설정값


#compiler-settings 지시어에 설정값을 설정할때는 #compiler-settings 지시어와 #end compiler-settings 지시어 사이줄에 넣어야 한다. 설정값에 대한 내용은 컴파일할 때 쓸 코드에 관해서는 Cheetah의 가이드를 참조하길 바라며, 여기서는 syntax settings에 관해서만 간략하게 설명하고 넘어가도록 한다. syntax settings은 문법에 관한 것으로 지시어 설정에 쓰이는 기호의 시작,끝 기호를 사용할 수 있으며 주석에 관해서도 같은 방법을 사용할 수 있다. 만약 C++ 스타일의 주석을 사용하고 싶다면 다음과 같이 compiler setting 을 설정하면 된다. 그렇지만 기존에 사용하던 ##, #* *# 방식의 주석은 사용할 수 없게 되니 사용에 주의하는 것이 좋다.


#compiler-settings

commentStartToken = //

multilineCommentStartToken = /*

multilineCommentEndToken = */

#end compilet-settings

<코드3> C++ 스타일의 주석을 설정할 수 있도록 사용하기


다른 설정값에 대해서는 한번씩 해보고 결과를 익혀두면 공동 작업시 능률을 기대할 수 있을 것으로 보인다.


10. 파이썬 코드 이스케이프

문법 : <%=expr%>, <% expr %>

앞서서 언급되었던 내용 중에는 실제 템플릿에 목적에 맞는 지시어들(#for, #if 등)도 있지만 템플릿답지 않게 만드는 지시어들도 몇 가지 포함되어 있었다. 이러한 지시어들 중에는 파이썬 코드만을 이스케이프 하는 방법도 있는데 파이썬 코드를 직접 템플릿 내에 구사하는 것은 올바르지 않다. 여러 데이터를 출력하기 위한 for문이나 출력을 결정하기 위한 if 문등은 예외가 될 수 있겠지만 말이다.


expr은 표현식을 의미하며 첫 번째 문법(<%=%>)은 값을 출력하는데 많이 쓰인다. 물론 여기서 이 부분은 앞서 언급되어진 #echo 지시어와 #silent 지시어와 동일한 기능을 수행한다.


11. Cheetah로부터 생성된 파이썬 모듈 제어

Cheetah는 템플릿을 컴파일 후에 최종적인 파이썬 모듈을 만들어 내는데 다음 2개 지시어는 파이썬 모듈을 수동적으로 실행할 때 파이썬 프로그램의 위치와 모듈의 엔코딩 값을 바꾼다.


지시어명 : #encoding

문법 : #ecoding UTF-8

모듈의 엔코딩을 지정하며 다음은 출력 예제를 보여준다.

result) # -*- coding: UTF-8 -*-


지시어명 : #shbang

문법 : #shbang #!파이썬 인터프리터 위치

모듈을 수동적으로 실행할 경우 파이썬 프로그램의 위치를 지정한다.

result) #!/usr/bin/env python


이 지시어는 기본적으로 다음의 값을 기본값으로 가져간다.

#!/usr/bin/env python


Tip : 템플릿 내에서 request 객체의 값 가져오기

템플릿 내에서 request 객체로 전달된 필드 값을 바로 가져올 수 있다. 다음과 같이 사용하면 된다.

${request.field('getArgs')}

여기서 getArgs는 실제 URL이나 POST 메소드로 전달될 필드명을 적어준다. 그러면 굳이 템플릿의 사전형 값에 추가하지 않아도 request 객체의 값을 받을 수 있게 된다.


spyce에서 cheetah 템플릿 사용하기

지금까지는 cheetah 템플릿의 문법에 치중하여 cheetah 템플릿을 알아보았다. 지금 알아볼 것은 spyce에서 cheetah 템플릿을 사용하는 것이다. spyce에서 Cheetah 템플릿을 사용하려면 다음과 같은 문법을 사용하면 된다.


문법 : te,plate.cheetah( file, [lookup] )

여기에서 lookup은 선택적 인자인데, 사전형 데이터를 인자로 받는다. 이 인자를 적지 않으면 스크립트 내에 있는 모든 인자의 값이 템플릿으로 전달된다. 이 방법으로 구현된 예제는 지금까지 알게 모르게 모든 예제가 그러했으니 지금 볼 예제는 템플릿으로 넣을 인자만 사전에 넣은 후 그 사전을 템플릿으로 전달해 보는 방법의 예제4를 살펴보고 그림 5의 실행 결과를 보자.


참고박스 -- 키워드 인자

예제4에는 키워드 인자의 사용을 볼 수 있는데, 필자가 이제까지 써놓은 문법들에는 모두 키워드 인자를 바로 사용할 수 있도록 되어 있다. 이때 키워드 인자는 튜플형 인자와 사전형 인자를 받을 수 있는데 메소드나 함수 정의시에 사용된 원형 이름으로 값을 넘길 수 있다. 물론 메소드나 함수에 따라 다르게 선언되어 있으므로 사용시 매뉴얼이나 소스코드를 충분히 살펴보아야 할 것이다. cheetah 함수를 예로 든다면 다음과 같이 키워드 인자를 넘길 수 있다.

예) template.cheetah(file="soeunlee.tmpl", lookup=[templateOutValue])

키워드 인자에 대해서는 파이썬 입문서에 보면 자세히 잘 나와 있으니 참조해보길 바란다.


--- (choiceargs.spy) ---

[[.import name=template]]



[[\

lookvalue = {'lookvalue':"123"}

]]


[[=template.cheetah('choiceargs.tmpl', lookup=[lookvalue])]]

--- (choiceargs.tmpl) ---

${lookvalue}

#try

${lookvalue2}

#except

#pass

#end try

<예제4> 선택적 인자만 템플릿에 전달하기


(choiceargs.png)

<그림5> (예제4)의 실행 결과


예제4를 유심히 보면 lookvalue 라는 변수에 사전형 데이터를 넣는데 이 사전형 데이터에 템플릿에 출력할 데이터를 모두 넣고 template를 출력할 때 lookup 키워드 인자에 넣어주면 템플릿엔 사전에 포함된 데이터만 출력되게 된다.


그리고 예제4의 choiceargs.tmpl에는 키워드 인자 전달과 상관없이 $lookvalue 만 적었는데도 불구하고 값이 출력되어져 있다. 그렇다면 전달될 때 사전 이름은 적지 않아도 되는 걸까? 답은 적지 않아도 된다이다. 템플릿으로 전달한 사전형 값은 이름, 값만을 템플릿에 전달하기 때문이다.


여기서 잠깐 --

Spyce와 함께하는 파이썬 웹 프로그래밍 2편에서 데이터베이스에서 반환되는 자료형은 사전형 데이터라는 것을 기억했다면 템플릿 인자로 한 번에 하나의 사전 인자만 전달할 수 없지 않나?라는 의문을 가질지 모르겠다. 그러나 이런 의문을 가진 독자가 있다면 무척 눈치가 빠르다고밖에 할 수 없을 것 같다. 이 연재에서는 파이썬 자료형에 모두 다루지 않았으나 파이썬 자료형은 List, Tuple, Dictionary 의 값에는 중첩된 자료형으로 만들 수 있다. 다시 말해 Dictionary는 자료들의 컨테이너 일뿐이고 이 안에 다른 사전형 데이터를 넣을 수 있다. 다음의 예제를 보면 쉽게 이해가 될 것이다.


myDictionary = {'name':'So Eun Lee'} // 일반적인 문자열 값

myDictionary['profile'] = rsProfile // rsProfile 은 사전형으로 이루어진 데이터베이스 반환값

위와 같이 스크립트에서 정의되고 myDictionary가 템플릿에 사전 인자로 전달되면 템플릿에선 다음과 같은 방법으로 사용이 가능하다.


// 템플릿 파일 내용

${name}


필드명 | 필드값

#for $key, $value in ${profile}

$key | $value

#end for


위와 같이 템플릿으로 사전형 데이터를 전달하는 것은 파이썬 데이터 타입인 사전형의 특성으로 인해 어렵지 않게 여러개의 사전형 데이터를 전달할 수 있게 된다.

---


지금까지 Spyce에서 파이썬 기반의 Cheetah 템플릿에 대해 알아보고 사용하는 것까지 마쳤다. 3회 동안 연재하면서 실질적인 예제보다 어떻게 하면 된다 라는 가이드만 독자들에게 제시해 준 것 같아 미련이 남는다. 지면이 조금 더 할애되었더라면 파이썬에서 직접 Cheetah 템플릿을 사용하는 것까지 하고 싶었는데 조금씩 편집 당하는 기쁨(??) 때문에 그러하지 못해 아쉽긴 하지만 여기까지 한 것만 해도 혼자서 장하다고 기뻐하고 있다. 원고해산의 기쁨은 곧 독자들에겐 멀고도 긴 웹 프로그래밍의 시간대로 나아가는 지평선이 아닐까 혼자서 중얼거리고 있다. “휴우 손이 다 떨린다~”

Spyce와 함께 하는 파이썬 웹 프로그래밍 2

Spyce와 데이터베이스 프로그래밍

이번호에서는 웹 프로그램에서 땔래야 뗄 수 없는 공생관계를 유지하는 데이터베이스를 파이썬에서 사용하는 방법과 Spyce에서의 데이터베이스 사용에 대해서 소개하고 그 인터페이스를 알아본다.

이상호 search5@gmail.com

현재 리눅스 엔지니어로 일하고 있으며, 웹과 그 기반 기술들에 대해 관심이 많다. 파이썬과 PostgreSQL에도 관심이 많아 항상 이 둘을 어떻게 하면 잘 사용할까 생각한다. 요즘은 동갑내기 여자 가수인 이소은을 쫓아다니며 어떻게 하면 고백할 수 있을까 고민 중이다.

연재순서

1회 2005.10 Spyce를 통한 PSP 프로그래밍
2회 2005.11 Spyce와 데이터베이스 연동
3회 Spyce와 Cheetah를 이용한 템플릿 사용

웹 프로그램이라는 것이 웹의 초기엔 그다지 비중이 크지 않았지만 점차 웹의 한계가 사용자와 대화하는 측면이라는 인식이 널리 퍼졌있었을땐 웹 프로그램도 많이 발전해 있었을 뿐 아니라 그 기반에 데이터라는 요소 자체도 웹 프로그램에선 중요시 되게 되었다. 이러한 웹 프로그램에서 데이터를 활용하기 위해선 데이터베이스라는 개념과 그 개념을 이용한 DBMS를 이용하게 된다. 사실 데이터를 이용하기 위해서 꼭 데이터베이스를 이용해야 하는 것은 아니지만 구조적인 시스템 및 효과적인 데이터 활용을 위해서 웹 프로그램에서의 데이터베이스는 필요한 존재라고 규정할 수 있을 것이다.

전편에서 잠시 언급한 바 있는 여러 파이썬 웹 프로그래밍 방법이나 툴에 대해서 설명한것과 마찬가지로 데이터베이스 또한 같은 상황을 가지고 있다. 하나의 데이터베이스만 사용해야 하는 것은 아니며 선택할 수 있는 DBMS 및 다양한 DB 접근 인터페이스가 존재한다. 일반적으로 DB에 바로 접근해서 사용하는 인터페이스와 윈도우의 ODBC, MS의 ADODB, PHP의 PEAR, Perl 의 DBI 같이 특정 레이어를 사용한 인터페이스가 존재한다.

일반적으로 이식하기 쉽게 하거나 유지 보수를 쉽게 할 수 있는 방법은 DB 에 상관없는 레이어를 사용하는 편이 좋다. 중간에 데이터베이스 DBMS의 버전에 따라 특정 기능이 추가될 경우 사용하고자 하는 DB의 인터페이스의 특정 기능 때문에 다른 데이터베이스로 이전할 경우 그 작업량이 프로그램에 상대적으로 많아질 수 있다는 사실이다. 이러한 특성을 이식성이라고 부른다. 자 이제부터 본격적으로 Spyce와 Database 를 같이 사용하는 방법에 대해 여러분과 함께 알아보도록 한다.

DBMS

우선 Spyce에서 Database 를 사용하기 전에 DBMS에 대해 잠시 알아보도록 한다. DBMS의 어원은 1963년에 시스템 디벨로프사에서 개최한 ‘Development and Management of Computer - Center Data Bases' 심포지엄에서 처음 사용하였으며 데이터베이스의 독립성 개념을 도입한 데이터베이스의 모체는 1963년에 제너널 일렉트릭사에서 개발한 ’Integrated Data Store에서 찾아볼 수 있다. 또한 데이터베이스 표준화 작업은 1965년의 CODASYL의 DBTG에서 시도되었다.

그 후 데이터베이스에 대한 연구가 계속되었는데 1970년 E.F.Codd에 의하여 제안된 데이터베이스 모델인 관계형 데이터베이스가 나타남으로서 데이터베이스 시장엔 데이터베이스 설계 및 운용에 있어 일대 전기를 가져오게 되었다. 데이터베이스 시스템의 모델은 크게 몇 가지가 존재한다. 객체지향 데이터베이스, 망 구조 데이터베이스 시스템, 계층 구조 데이터베이스 시스템, 관계형 데이터베이스가 현재 운용중이거나 나타난 모델이다. 현재 가장 많이 사용하고 있는 시스템은 관계형 데이터베이스로 현존하는 DBMS의 대부분이 사용중이다. 가장 대표적인 DBMS로는 Oracle, MS-SQL, MySQL, PostgreSQL 등이 있다. 이후 1986년 DBMS에 질의하기 위한 언어로 SQL(Structured Query Language)이 표준 언어로 채택되었다.

SQL은 미 표준을 제정하는 ANSI와 국제 표준 기구인 ISO에 의해 SQL92, 93 등으로 표준이 제정되어 있다. SQL이 표준 관계형 데이터베이스 질의 언어이고 많은 관계형 DBMS가 채택하고 있지만 DBMS는 일부 기능구현을 위해 SQL에는 없는 자료형이나 함수를 포함하기도 한다. 그 반대로 SQL 정의엔 구현되어 있지만 DBMS에는 구현되어 있지 않은 것들도 있다. 이러한 것중 일부는 text 자료형이다. 그림 1은 관계형 데이터베이스 중 PostgreSQL의 홈페이지이다.

(picture-postgresql-homepage.png)
<그림1> PostgreSQL 홈페이지

데이터베이스가 가지는 장점

그렇다면 DBMS가 가지는 장점은 어떤 것이 있을까?

① 다중 사용자의 공유 및 보안이 가능하다.
 - 데이터베이스 시스템은 여러 사용자의 동시 접근을 관리하는 동시성 제어(concurrency control)가 가능하므로 같은 내용의 데이터를 여러 사람이 서로 다른 방법으로 동시에 공유하게 할 수 있다(대표적인 예로 웹에서의 데이터베이스 사용을 들 수 있다). 또한 데이터베이스에 대한 접근의 통제 및 개인 정보를 보호하는 보안(security) 등의 다양한 기능이 제공된다.

② 구조적 종속과 데이터 종속을 제거한다.
 - 데이터베이스 파일의 접근이 DBMS를 통해 자동적으로 처리됨으로써, 변경된 파일에 관계된 모든 프로그램을 수정해야 하는 부담에서 벗어날 수 있다. 즉 DBMS가 시스템으로부터 구조적 종속과 데이터 종속을 제거하며, 데이터를 저장하기 위한 효율적인 물리적인 구조를 생성하고 사용자가 입력한 데이터를 물리적 구조에 적합한 데이터로 변환을 한다. 따라서 사용자는 데이터를 항상 논리적 관점에서 볼 수 있고 프로그램 구현이 간단해진다.

③ 효율적인 검색이 가능하다.
 - 데이터베이스에서 데이터의 참조는 수록되어 있는 데이터 레코드들의 주소나 위치에 의해서가 아니라 데이터의 내용, 즉 데이터가 가지고 있는 값에 따라 참조된다. 따라서 SQL(Structured Query Language) 같은 언어를 사용하면 사용자의 질의를 효율적으로 처리하는 질의처리(query processing)가 가능하며, 참조하길 원하는 데이터의 자격 요건을 제시하면 이 조건을 만족하는 모든 레코드들은 하나의 논리적 단위로 취급되고 접근된다.

관계형 데이터베이스 구조

(picture-relation-database-structured.jpg)
<그림2> 관계형 데이터베이스의 구조

그림2에는 관계형 데이터베이스의 구조가 나와 있는데 그 모양은 표와 비슷한 모양을 가지고 있다. 표의 구조가 아련하다면 초중고 시절에 지겹게도 보아왔던 시간표 형태를 생각하면 적당한 모습을 가지고 있다고 생각하면 될것이다.

관계형 데이터베이스에서는 한 개체를 테이블이라 이름짓고 다른 말로는 릴레이션이라고 부르기도 한다. 그림 2에서 가로로 몇 개의 값이 나열되어 묶여 있는 것을 레코드(Record)라 하며 다른 말로 tuple이라 부르기도 한다. 테이블에서는 Row 라고 부른다. 반대로 세로로 나열되어 묶여있는 것을 필드(Field) 라고 하며 테이블에서는 Column이라고 부른다. 그림2에서는 이러한 것을 그림으로 표현하여 보여주고 있다.

테이블에서 레코드를 구분짓는 값으로 어떠한 레코드에서도 겹치지 않고 중복되지 않는 값을 기본 키(Primary Key)라고 한다. 이 기본 키는 각 Record에서 유일무이한 값이며 테이블 정의시에 PRIMARY KEY(FieldName)을 이용해 정의하게 된다. 기본 키(Primary Key)는 테이블 정의 구문에 단 1개만 정의할 수 있다.

mysql은 윈도우와 리눅스에서 데이터베이스와 테이블 생성시 이름에 대해 주의할 필요가 있다. 특수문자를 쓰지 말아야 한다는 것 외에도 대소문자를 구별한다는 것인데, 실제 서버에서 데이터베이스를 개발할 경우 서버의 운영체제가 윈도우인지, 리눅스인지 구분해놓을 필요는 있다. 실험결과 PostgreSQL은 운영체제가 윈도우이거나 리눅스일 경우에도 대소문자는 구분하지 않았다.

그럼 잠깐 테이블 이름과 필드 이름 생성 규칙에 대해 잠시 알아보고 가자. 데이터베이스는 데이터를 넣기 위해서 테이블과 필드를 생성해야 하는데 이것에 대해선 뒤에서 조금 더 알아보기로 하고 지금은 테이블과 필드를 생성할 때 적용되는 다음과 같은 특징이 있다

1. DBMS의 예약어는 사용할 수 없다(SQL문을 구성하는 select, insert, delete 등)
2. 특수문자는 사용할 수 없다
3. 공백 문자를 사용할 수 없다.
4. 테이블과 필드 이름 길이에 64개의 제한이 있다(DBMS에 따라 조금씩 다를 수 있다. 기준은 PostgreSQL)
5. 이름은 숫자와 알파벳, _(언더라인)으로만 구성할 수 있으며 숫자로 시작할 수 없다

그러나 예외적인 법칙은 있다. 바로 1번과 3번, 하이픈에 관한 것인데 테이블과 필드를 생성할 때 더블 쿼트(")로 둘러 쌓여주면 허용이 된다는 것이다. 이렇게 더블 쿼트로 선언된 테이블 또는 필드는 반드시 사용할때도 더블 쿼트(“)로 둘러서 사용을 해주지 않으면 사용할 수 없다.

create table "test-1" (idx int);
select * from "test-1";
create table test1 ("id1-x" int);
select "id1-x" from test1;
create table test1 ("id ref" int);
select "id ref" from test1;
<예제1> 하이픈과 DBMS 예약어 사용

예제1에서 필드 이름에 하이픈을 사용한 select 구문에서는 더블 쿼트(“)를 써야만 하는 이유를 쉽게 유추할 수 있는데, 하이픈은 우선 select 구문에서 수치연산을 하기 때문인데, 만약 다음과 같이 더블 쿼트를 빼고 사용한다면 id1 필드에서 x 필드의 값을 뺀 결과치가 임의 컬럼으로 출력될 것이다.

select id1-x from test1;

?column?
------------
6260
<예제2> 필드 이름에 하이픈을 포함한 select 구문의 결과

예제2에서 사용한 select 구문에서 연산의 종류를 +, / 등으로 변경시켜도 정상적으로 동작하는 것을 확인할 수 있을 것이다.

DBMS를 자유롭게 다루는 마법사. SQL

앞서 대부분의 데이터베이스가 관계형 데이터베이스 모델을 사용하고 질의 언어로 SQL을 사용한다고 하였다. 그렇다면 SQL은 어디까지 DBMS에 대해 힘을 미치고 있을까? 여기에서 규정하는 SQL은 DBMS를 자유롭게 다루는 질의 언어이다.

다시 말해 DBMS를 자유롭게 다루는 열쇠는 SQL이라고 보고 있다. 그렇지만 SQL이 DBMS 자체를 자유롭게 강력하게 다루는 열쇠는 아니다. SQL은 어디까지나 DBMS 내의 데이터를 자유롭게 다루는 언어이기 때문이다.

SQL에는 크게 DDL, DML, DCL로 나뉘는 구문들이 존재하게 된다.

분류 SQL 구문
DDL CREATE, DROP, ALTER 등
DML SELECT, INSERT, DELETE, UPDATE 등
DCL GRANT, REVOKE 등

<표1> DDL, DML, DCL로 나뉘는 구문.

우선 DDL이나 DML이니 단어는 정보처리기사나 산업기사의 데이터베이스 항목에 자주 출현하는 단어들로 본래 뜻은 다음과 같다

DDL : Data Definition Language
 - 데이터베이스, 테이블을 생성할 때 사용하는 언어이다. 이 분류에는 생성과 삭제에 관한 SQL 문, 테이블과 데이터베이스, 유저 생성, 변경 등이 포함된다.

DML : Data Manipulation Language
 - 데이터를 조작할 때 사용하는 언어이다. 이 분류에는 데이터를 조건에 따라 선택하거나 삽입, 삭제 하는 SQL 문이 포함된다.

DCL : Data Control Language
 - 테이블, 필드 등에 관한 접근 권한 등을 제어하는 언어이다. 이 분류에는 테이블 등에 접근권한을 제어하는 SQL 문이 포함된다.

데이터를 조작하기 위해서 DML만을 다룰텐데 지면에서는 DDL과 DCL에 대해서는 다루지 않고 SQL 에 관한 서적을 참조하기 바란다. DML에서는 크게 4가지의 구문이 가장 많이 쓰이는 형태이다.

SELECT .. FROM .. WHERE .. GROUP BY .. ORDER BY

INSERT INTO .. VALUES ..

UPDATE SET .. WHERE

DELETE FROM .. WHERE

표2는 DML 구문에 관한 설명인데, SELECT, INSERT, UPDATE, DELETE 에 대한 설명을 볼 수 있다.

SQL 문 설명
SELECT 하나 또는 그 이상의 테이블로부터 필드를 검색한다.
FROM 필드를 가져오거나 레코드를 삭제할 테이블을 지정한다. SELECT, DELETE 구문에서는 반드시 명시되어야 한다.
WHERE 검색할 열에 대한 조건을 지정한다. 즉, 조건에 맞는 특정한 열만 검색할 경우 사용한다.
GROUP BY 레코드를 그룹으로 나누기 위한 조건을 지정한다.
ORDER BY 레코드를 정렬하기 위한 조건을 명시한다.
INSERT 지정한 테이블에 데이터를 추가한다.
UPDATE 지정한 테이블의 데이터를 갱신한다.
DELETE 지정한 테이블에서 데이터를 삭제한다.

<표2> DML 구문 설명

표2에서는 DML 구문에 관한 설명을 볼 수 있다. DML 구문은 절이라는 단위가 있는데 다음과 같은 SQL 문은 WHERE 절의 내용은 a필드의 값이 1인 요소만 뽑아내라고 말한다.

select * from test1 where a='1';

SELECT 문에는 여러 절이 복합적으로 사용될 수 있는데, 앞에서 언급되지 않는 테이블 조인에 필요한 절도 포함될 수 있다. SELECT 구문에서는 GROUP BY 절과 ORDER BY 절에서 주의해야 할 점이 있는데 ORDER BY 절은 반드시 SELECT 문의 가장 끝에 와야 한다는 점이다. 다른 하나의 주의할 점은 GROUP BY 절 뒤에는 WHERE 절이 올 수 없다. 따라서 조건을 명시하려면 HAVING 절을 사용해야 한다.

레코드를 삭제하는 DELETE 문과 레코드를 업데이트 하는 UPDATE 문은 WHERE 절만이 사용가능하다. 반면에 INSERT INTO 문은 데이터를 삽입하는 문으로서 조건을 명시하는 절이 필요치 않다.

WHERE 절에는 필요한 연산을 수행할 수 있다. 일반적으로 같다면(=), 보다 크다면 (>=), 보다 작다면 (<=), LIKE, 범위 연산인 Between 연산 등을 수행할 수 있다.

이제 SQL에 관해서 몇 가지 예제를 알아보고 이제 파이썬에서 DB를 접근하는 방법에 대해 알아보자. 예제3은 테이블 생성 및 select, insert, into, delete, drop 에 관한 사용방법을 볼 수 있다.

// 테이블 생성
create table books (
idx serial,
title varchar(255),
EditionNumber char(1),
Copyright char(4),
PRIMARY KEY(idx)
);

// 데이터 삽입
insert into books (title, EditionNumber, Copyright) values ('Internet and World Wide Web How to Program', '2', '2002');

insert into books(title, EditionNumber, Copyright) values ('Java How to Program', '4', '2002');

// 데이터 선택
select * from books where EditionNumber='2';

idx |                        title                                                             | EditionNumber  | Copyright
----+----------------------------------------------------------------------+------------------------+--------
1    | Internet and World Wide Web How to Program    |2                              | 2002

// 데이터 수정
update books set Copyright='2004' where title='Internet and World Wide Web How to Program';

// 수정된 데이터 확인
select * from books where EditionNumber='2';

idx |                        title                                                             | EditionNumber  | Copyright
----+----------------------------------------------------------------------+------------------------+--------
1    | Internet and World Wide Web How to Program    |2                              | 2004

// 데이터 삭제
delete from books where EditionNumber='2' and Copyright='2004';

// 데이터 확인
idx | title
----+----
(0 rows)

// 테이블 삭제
drop table books;
<예제3> SQL 사용 예제

파이썬 DB API

파이썬 DB API는 처음에 언급한 바와 같이 크게 2가지 방식이 존재한다. DB 별로 제공되는 개별 인터페이스와 모든 데이터베이스에 공통적으로 적용할 수 있는 인터페이스가 그 것인데, 이 둘은 DB 에 접근해서 사용하는 것과는 같은 노선을 유지하지만 그 문법은 서로 조금씩 다르다.

여기에서는 PostgreSQL DBMS를 기준으로 데이터베이스에 의존적인 코드와, 파이썬 DB API 2.0을 사용한 코드와 비교해볼 것이다.
필자가 파이썬에서 DB를 연결하기 위해서 사용한 환경은 Debian Etch(testing) 버전이며 데이터베이스는 PostgreSQL 7.5를 사용하였다.

파이썬에서 PostgreSQL에 연결하기 위해선 여러 인터페이스가 있지만 그중 현재까지 활발히 개발되고 있는 PyGreSQL을 사용하기로 결정하였다. PyGreSQL은 PostgreSQL이 Postgre95로 개발되고 있었을때 개발된 모듈인데 현재의 모듈 이름은 PostgreSQL의 이름에 맞게 PyGreSQL로 변경되었다.

(picture-pygresql-homepage.png)
<그림3> PyGreSQL 홈페이지

PyGreSQL 홈페이지에 가면 PyGreSQL 을 다운로드 받을 수 있다.

PyGreSQL 설치

PyGreSQL은 Linux 환경에서 RPM과 tar로 설치가 가능하며, 필자의 컴퓨터에선 다음의 명령을 내려 PyGreSQL과 Python, PostgreSQL을 설치하였다.

# apt-get install python python-pygresql postgresql

많은 독자분들의 환경에 맞게 컴파일 환경을 구성해서 보여주어야 하지만 지면상 보여주지 못함에 양해를 바란다.

PyGreSQL 들여다 보기

파이썬에서 DB API는 각 모듈이 개별적으로 제공하게 된다(이는 PHP가 PEAR가 개별 라이브러리를 제어하는 것과 반대이다). 현재 개발되고 있는 파이썬 DB 인터페이스 프로젝트들은 대부분이 Python DB API 2.0을 따라서 개발되고 있다.

PyGreSQL은 크게 3가지의 모듈을 제공한다. 표3에는 모듈에 대한 설명이 나와 있다.

모듈 설명
pg 가장 원시적인 코드로 PHP에서의 pg_connect 등과 데이터베이스에 의존적인 모듈이다.
pg.DB pg의 wrapper로 pg와 같이 데이터베이스에 의존적이다.
pgdb Python DB API 2.0에 맞게 개발된 PyGreSQL 모듈이다.

<표3> PyGreSQL 모듈

단 pgdb 사용시 접속문자열의 경우엔 데이터베이스에 의존적인 인자를 사용하므로 미리 해당 데이터베이스의 접속 문자열을 알아둘 필요가 있다. 이 인자는 데이터베이스 시스템의 C 인터페이스에 보면 나와있다.

PyGreSQL db 모듈

PyGreSQL의 db 모듈은 데이터베이스에 의존적인 모듈인 만큼 PostgreSQL에 의존적인 메소드나 편의성을 위해서 만들어진 메소드가 몇 가지가 존재한다. 표4는 PyGreSQL에서 생성되는 객체에 제공되는 주요 메소드를 설명한 내용이다.

pg_module - pg에서 처음 제공되는 모듈에서 사용할 수 있는 Method
connect Syntax : connect(dbname, host, port, opt, tty, user, passwd)
데이터베이스로 연결을 시도하며 pgobject 객체를 리턴한다. 이때 인자는 필요한 것만 키워드인자로 넘겨줄 수 있다.
close Syntax : close() connect로부터 반환된 pgobject
결과를 닫는다. 객체를 완전히 삭제하려면 del 문을 사용해서 객체를 삭제한다.
pgobject - connect 메소드로부터 리턴되는 객체에서 사용할 수 있는 Method
query Syntax : query(command)
데이터베이스로 SQL문을 질의한다. 리턴값으로 pgqueryobject 객체를 반환한다. 결과 객체에 소켓으로 직접 데이터를 보낼 수 있다.
close Syntax : close()
query 메소드로부터 반환된 pgqueryobject를 닫는다. 객체를 완전히 삭제하려면 del 문을 사용해서 객체를 삭제한다.
inserttable Syntax : inserttable(table, values)
테이블에 데이터를 삽입한다. values에는 table의 필드 정의 순서에 따라 값이 들어 있는 리스트(list) 또는 튜플(tuple)을 넣는다.
pgqueryobject methods - pgobject의 query 메소드로부터 리턴되는 객체의 Method
getresult Syntax : getresult()
질의된 결과를 리스트에 튜플이 포함된 형태로 반환한다.
반환값 예) [(10103, 3843), (10103,3844343), (348248, 438432)]
dictresult Syntax : dictresult()
질의된 결과를 리스트에 사전 형태로 반환한다.
반환값 예) [{'x':3843, 'id1':10103}, {'x':3844343, 'id1':10103}, {'x':438432, 'id1':348248}]
listfields Syntax : listfield()
필드명을 반환한다. 반환값은 튜플이다.
반환값 예) (‘id1', 'x')
fieldname Syntax : fieldname(i)
인자로 받은 i 위치의 필드 이름을 반환한다. 반환값의 형태는 string이다. 필드번호는 0번부터 시작한다.
반환값 예) id1
fieldnum Syntax : fieldnum(name)
인자로 받은 name 의 필드 번호를 반환한다. 반환값의 형태는 numeric이다. 필드번호는 0부터 반환한다.
반환값 예) 0
ntuples Syntax : ntuple()
리턴된 결과의 record 개수를 반환한다.
반환값 예) 3

<표4> pg 모듈의 객체 분류에 따른 메소드

 파이썬은 문법이 함수 기반이 아닌 객체지향 기반인 클래스를 사용하므로 각각의 리턴되는 객체에 따라 사용할 수 있는 메소드가 달라진다. 따라서 표4에서 나타내는 pgobject, pgqueryobject 객체에서 사용할 수 있는 값을 확인해야 한다.

표4에서는 생략했지만 pglargeobject 객체에서 제공되는 메소드에 대한 내용도 따로 나와있다. 그 밖에 여러 사용가능한 메소드가 있지만 지면상 자세한 것은 PyGreSQL에서 배포되는 README.txt 파일을 참조하기 바란다.

다음에 나오는 예제4는 PyGreSQL의 pg 모듈을 사용한 프로그래밍 예제이다.

// pgobject 객체 생성
pool = pg.connect(dbname="leesoeun", host="localhost", user="shlee", passwd="xxx")

// pgqueryobject 객체 생성
result = pg.query("select * from guestHistory")

// getresult 값 추출
getresult = result.getresult()
print getresult

// dictresult 값 추출
dictresult = result.dictresult()
print dictresult

// ntuples 값 추출
print result.ntuples()

// pgqueryobject 객체 close 및 삭제
result.close()
del result

// pgobject 객체 close 및 삭제
pool.close()
del pool
<예제4> pg 모듈을 사용한 프로그래밍 예

예제 4에서 간단하게 pg 모듈을 직접적으로 사용하는 예를 알아보았다. 다음에 알아볼 것은 pg 모듈을 감싼(wrapper) 모듈인 pg.DB 이다. pg.DB는 pg 모듈을 감싸서 최대한 사용자가 쉽게 사용할 수 있도록 만든 모듈이다. 표5에는 pg.DB 모듈의 주요 메소드를 나타내었다.

pg.DB 메소드
pg.DB Syntax : pg.db(dbname, host, port, opt, tty, user, passwd)
표4의 connect 메소드에서 사용된 인자를 동일하게 사용한다. pgobject 객체를 생성한다.
insert Syntax : insert(table, a)
새로운 record를 삽입한다. a는 데이터베이스에 넣을 dictionary 값을 넣어주면 된다.
clear Syntax : clear(table, [a])
인자로 주어진 a가 없으면 테이블의 전체 행의 값을 0으로 만들어 dictionary(사전)으로 반환한다. 수행결과는 데이터베이스에 반영되지 않는다. a는 사전형태의 값이다.
close Syntax : close()
pgobject 객체를 닫는다.

<표5> pg.DB 의 메소드

pg.DB 모듈은 pg 모듈을 감싼 것이라고 잠시 언급한 바 있는데 pg.DB 의 자체 기능 뿐 아니라 기존에 pg에서 사용했던 메소드를 제공함으로서 pg 객체를 그대로 다시 활용이 가능하다. 예) query, getresult, dictresult 등

예제5는 pg.DB 모듈을 사용한 예제를 보여준다. 일부 메소드는 제대로 동작하지 않아 여기서는 생략하였다. 향후 기회가 되면 python 으로 DB 프로그래밍을 할때 다루지 않을까 싶다.

// pgobject 객체 생성
pool = pg.DB(dbname="leesoeun", host="localhost", user="shlee", passwd="xxx")

// 새로운 데이터 삽입
newoid = pool.insert('freeboard', {'title':‘오늘 하루는 어떠셨나요?’, 'contents':'월요일이 끝났네요. 몸은 피곤하지 않으신가요?‘})
print newoid // pgsql에 값을 넣었을때는 oid값을 반환한다.

// 특정 값을 가지는 레코드들을 0으로 초기화 한 값 반환
clearDict = pool.clear('guestHistory', {'date':20051015'}
print clearDict
{'date':0}

// pg.DB close
pool.close()
<예제5> pg.DB 모듈을 사용한 프로그래밍 예제

이제 알아볼 내용은 pgDB 모듈로 파이썬 DB API 2.0을 따르는 메소드를 가진 모듈이다. 이 글의 가장 앞 부분에서 파이썬 DB API를 사용해야 하는 이유를 역설했는데, 이 글을 읽기 위해 학수고대했다면 독자분들에게 이렇게 늦게 진행시켜서 미안한 마음을 전한다 :-

PyGreSQL을 설명하면서 파이썬에서 DB API는 DB 인터페이스에서 제공한다고 언급했는데, DB 인터페이스에 따라 파이썬의 DB API를 제공하지 않을 수 있다. PyGreSQL은 현재 정의되어 있는 파이썬 DB API 2.0 규격을 충실히 따르는 모듈과 메소드를 제공하고 있다.

이 모듈을 사용하기 위해서 파이썬에서 다음과 같은 명령을 내려주어야 한다.
import pgdb

언뜻 보면 앞서 나온 pg.DB와 비슷해 보이지만 모듈명이 pgdb인 것에 주의해서 사용해야 한다. 표6은 pgdb에서 사용 가능한 주요 메소드를 언급하고 있다.

Module Interface
.connect Syntax : connect(dsn, database, host, user, password)
데이터베이스에 접속한다. Connection Objects 를 반환한다. 접속인자는 dsn을 넣을 경우 부분적으로 host, database 등을 뺄 수 있다.
connection objects
.close Syntax : close()
connect 메소드가 반환한 connection objects를 닫는다.
.commit Syntax : commit()
cursor objects의 execute 를 실행한 후 데이터베이스에 최종적으로 커밋한다. 트랜잭션(Transaction)이 지원되는 데이터베이스만 가능하다.
.rollback Syntax : rollback()
cursor objects에서 execute 를 실행한 후 반영사항을 없애고 싶을 경우 이 메소드를 사용할 수 있다. commit 메소드와 같이 트랜잭션(Transaction)이 지원되는 데이터베이스만 가능하다.
.cursor Syntax : cursor()
Cursor Objects를 반환한다. SQL 문의 결과는 Cursor Objects에서만 실행할 수 있다.
cursor objects
.description Syntax : description()
execute에 의해 실행된 select 문의 테이블의 필드의 속성을 반환한다. execute에 의해 select 문이 실행된 다음에 실해야 한다.
반환값 : (필드명, 데이터형 코드, 표시크기, 내부크기, 정확도, 비율(string에선 의미없다), Null 가능 여부)
반환값 예) [('id1', 'int4', None, 4, None, None, None), ('x', 'int4', None, 4, None, None, None)]
.rowcount Syntax : rowcount
execute 의 결과 행 수를 반환한다. execute 메소드에 의해 select 문이 실행된 이후여야 한다.
.close Syntax : close()
Cursor Objects를 닫는다.
.execute Syntax : execute(command)
데이터베이스에 질의를 던지는 메소드이다. select 문을 실행했을 경우 description, fetchone, fetchmany, fetchall 을 사용할 수 있다. 이 메소드는 반환값이 없다.
.fetchone Syntax : fetchone()
execute의 실행결과에서 한 record를 가져온다. 실행할 경우 자동적으로 다음 레코드를 가져올 수 있게 된다.
.fetchmany Syntax : fetchmany([size=cursor.arraysize])
execute의 실행결과에서 다수의 행을 가져온다. 인자에는 숫자를 넘겨주거나 size=1 과 같은 식으로 인자를 지정할 수 있다. 지정하지 않을 경우 Cursor Objects의 arraysize 값을 반환한다.
.fetchall Syntax : fetchall()
execute의 실행결과의 전체 레코드를 가져온다. fetch* 메소드에서 한가지 눈여겨 볼 수 있는 결과는 pg 모듈에서 전체 레코드를 가져올 경우 일부 메소드는 튜플 형태로 반환하거나 사전 형태로 반환하기도 하지만 cursor 객체의 fetch* 메소드는 순수하게 리스트 형태로 값을 반환한다.
.arraysize Syntax : arraysize
fetchmany 메소드에서 사용되며 몇 개의 row를 가져올 것인지 지정한다.

<표6> pgdb의 주요 메소드

표6에서는 다루지 않은 메소드가 몇 가지 있지만 지면상 할애하지 못해 아쉬운 감이 있다. 표6에서 다룬 메소드 중에 fetch* 메소드의 특이한 점이 있는데, 예제 6을 보면 이해가 쉬울 것이다.

// 전체 테이블 내용
10103, 3844323
82838, 7277
949, 8599

// fetchone 실행(커서 객체의 execute가 실행되었다고 가정한다)
print cursor.fetchone()
[10103, 3844323]

// fetchmany 실행(arraysize는 1로 가정)
print cursor.fetchmany()
[[82838, 7277]]

// fetchall 실행
print cursor.fetchall()
[[949, 8599]]

// fetchone 실행
print cursor.fetchone()
[]
<예제6> fetch* 메소드의 실행

예제6에서 모든 결과를 주시할 필요가 있는데, 처음 하나는 값의 출력 순서는 테이블의 출력순서에 따른다. 다른 하나는 한번 fetch* 메소드를 실행하면 이미 출력한 값은 다시 출력할 수 없다는 것이다. 따라서 마지막에 전체 테이블 행이 3개인데, 이미 fetch* 메소드를 3번을 썼으니 마지막 fetchone을 실행하면 결과가 없다고 나오게 되는 것이다. 이 경우 해결방법은 cursor 객체에서 execute 메소드를 다시 한번 실행해주는 것이다. 하지만 웹을 상대로 했을 경우 이미 출력한 값으로 다시 거슬러 올라갈 필요가 있을까?라는 의문엔 없다라고 말하고 싶다.

이로써 파이썬 DB API 2.0를 사용하는 방법까지 모두 알아보았다. 이제 남은 부분은 전 월에서 다루지 못했던 spyce의 pool 객체를 사용하는 방법과 지금까지 배운 파이썬 DB API와, pg 모듈을 이용해서 spyce에서 사용하는 방법을 알아볼 것이다.

Spyce Pool

Spyce에는 Pool이라는 서버 객체가 제공된다. 뭐하는 놈인가 하면 서버측에 자원을 저장해놓은 것이다. 비슷한 개념으로 함수의 실행이 끝난 다음에도 값을 가지고 있는 정적변수를 그 예로 들 수 있다.

Spyce에서 pool은 도구가 제공하는 별도의 모듈인데, 이 모듈을 이용해서 서버측 자원을 이용할 수 있게 된다.

다음의 예제7은 spyce의 pool 을 이용한 프로그래밍 예이다.

[[.import names="pool"]]
<html><body>
  The pool module supports long-lived server-pooled objects,<br>
  useful for database connections, and other variables<br>
  that are expensive to computer.<br>
  [[    if pool.has_key('foo'):
      print 'Pooled object foo EXISTS.'
      pool['foo'] = pool['foo'] + 2
    else:
      pool['foo'] = 1
      print 'Pooled object foo CREATED.'
  ]]
  <br>
  Value: [[=pool['foo'] ]]<br>
</body></html>
<예제7> spyce의 pool을 이용한 예제

예제 7의 결과를 실행해보면 처음엔 그림 4와 같은 실행 결과 화면을 볼 수 있다.

(picture-spyce-pool-created.png)
<그림4> spyce pool 처음 실행결과

예제 7을 pool.spy로 저장후에 실행하면 처음엔 pool 모듈에 created 된 이후에 다시한번 pool.spy를 실행하면 그림5에 보이는 화면을 볼 수 있다.

(picture-spyce-pool-exists.png)
<그림5> spyce pool 2번째 실행결과

프로그램 실행이 만료된 후에도 서버에 자원을 저장하게 되므로 서버측에 저장해야 하는 데이터가 있다면 유용하게 사용할 수 있게 된다.

pool 모듈에서 사용할 수 있는 Operation(연산)이 7개의 연산이 제공되는데 각 Operation은 사전 데이터형에서 제공하는 것과 크게 다르지 않다.

pool 모듈에서 제공하는 연산의 종류
get, set, delete, has_key, keys, values, clear

상황에 따라 pool 모듈을 자유롭게 쓰기 위해서 위의 연산은 필요한 경우가 있을 것이다.

그러나 spyce의 pool에는 아직 치명적으로 생각되는 단점이 있는데, 한 클라이언트에 하나의 pool 이 아닌 여러 클라이언트가 접속했을때 pool은 초기화되지 않는다. 다시 말해 클라이언트에 상관없이 영속성을 지닌다는 것인데, 서버측에 pool은 오로지 하나만 존재할 수 있다는 것이다. 따라서 만약 이것을 데이터베이스의 커서 객체에 응용하려면 현재로선 추천할 수 없다.

그럼 서버측에서 pool는 어떻게 생성될까? 이 질문에 대해서는 리눅스일 경우 /tmp 디렉토리에 보면 spypool.pickle 이라는 파일이 생성되어 있는 걸 확인할 수 있다.

물론 이 파일은 사용자가 열어도 확인할 수 없는 형식으로 되어 있는데, 이미 눈치 빠른 독자라면 알아챘겠지만 이 파일은 파이썬의 피클링으로 인코딩되어 있다. 다시 말해 프로그램이 pool 요청을 받을 때마다 이 피클링된 파일을 계속 요청하게 되는 것이다. 그림6에는 이것에 대한 구조도가 나와있다.

(picture-pool-structured.png)
<그림6> pool의 서버 구조도

현재 pool 의 주 용도는 웹 게시판에 쓸 수 있는 데이터베이스 커서 객체가 아닌 방문자 통계치 등에 더욱 유용하게 사용할 수 있을 것으로 보인다. 향후에 이것에 관한 패치가 나올 경우 웹 게시판에도 무척 유용할 것으로 보인다.

Spyce와 파이썬 DB API 를 사용해서 프로그래밍 하기

앞서서 파이썬의 DB API를 사용해서 데이터베이스에 의존적인 코드와 파이썬 DB API 2.0 규격에 충실한 코드 작성 방법등을 알아보았다. 이제 할 일은 이것을 spyce에서 조합해서 데이터베이스에서 사용하는 방법을 알아볼 것이다.

spyce와 파이썬 DB 인터페이스의 사용

spyce에서 데이터베이스를 사용하기 위해서 가장 먼저 할 일은 모듈을 임포트 하는 일이다. 물론 여기서 모듈은 spyce 모듈이 아닌 파이썬에서의 모듈인데 모듈을 불러오는 방법이 다르므로 쉽게 가려낼 수 있다.

파이썬의 모듈 로드 : [[import pg]]
spyce의 모듈 로드 : [[.import name="pool"]]

파이썬의 모듈을 spyce에서 불러오기 전에 어떤 DB 모듈을 사용할 것인가 결정하는 것은 무척 중요한 일이다. 필자의 경우엔 호환성을 위해서 파이썬 DB API 2.0을 사용하기로 한다. 예제8은 파이썬 DB API 2.0 모듈을 불러와서 DB 에 연결하고 끊는 작업을 나타낸 예제이다.

[[-- PyGreSQL의 DB API 2.0 모듈 로드 --]]
[[import pgdb]]

[[-- 데이터베이스 접속 --]]
[[objConn = pgdb.connect(host="localhost",database="selee" user="shlee",password="xxxx") ]]

[[-- 데이터베이스 연결종료 --]]
[[objConn.close()]]
<예제8> 파이썬 DB API 2.0을 이용해 spyce에서 Connection을 수행한 예제

예제8에서 간단하게 데이터베이스에 접속하고 접속을 종료하는 예를 보였다. 파이썬에서 사용하던 방법과 동일한 문장을 사용하지만 다른게 있다면 문장의 앞뒤에 [[, ]] 로 감싸서 spyce 문장임을 확실히 했다.

다음 보여줄 예제9는 데이터베이스에 있는 내용을 웹에 뿌려주는 역할을 한다.

[[-- PyGreSQL의 DB API 2.0 모듈 로드 --]]
[[import pgdb]]

[[-- 데이터베이스 접속 --]]
[[objConn = pgdb.connect(host="localhost",database="selee" user="shlee",password="xxxx") ]]

[[-- 커서 획득 --]]
[[ cursor = objConn.cursor()]]

[[-- 도서 목록 질의 --]]
[[ cursor.execute("select * from books") ]]

[[-- 도서 목록 출력 --]]
<table>
<tr>
<th>도서명</th>
<th>출판사</th>
</tr>
[[ for title, press in cursor.fetchall(): { ]]
<tr>
<td>[[=title]]</td>
<td>[[=press]]</td>
</tr>
[[ } ]]

[[-- 커서 종료 및 삭제 --]]
[[cursor.close()
del cursor
]]

[[-- 데이터베이스 연결종료 및 삭제--]]
[[objConn.close()
del objConn
]]
<예제9> 데이터베이스 테이블의 내용 출력

예제 9에서는 테이블의 내용을 질의해서 얻어진 내용을 출력하는 스크립트이다. 여기서는 테이블 전체 내용을 가져오는 코드인데, 여기서 실제 테이블을 출력해주는 부분의 코드는 1회에서 다뤘던 람다식을 이용해 예제10과 같은 코드로 만들 수도 있다.

[[-- PyGreSQL의 DB API 2.0 모듈 로드 --]]
[[import pgdb]]
[[-- 데이터베이스 접속 --]]
[[objConn = pgdb.connect(host="localhost",database="selee" user="shlee",password="xxxx") ]]

[[-- 커서 획득 --]]
[[ cursor = objConn.cursor()]]

[[-- 테이블 람다식 --]]
booktable = [[spy! data:
<table>
<tr>
<th>도서명</th>
<th>출판사</th>
</tr>
[[ for title, press in cursor.fetchall(): { ]]
<tr>
<td>[[=title]]</td>
<td>[[=press]]</td>
</tr>
[[ } ]]
]]

[[-- 도서 목록 질의 --]]
[[ cursor.execute("select * from books") ]]

[[-- 도서 목록 출력 --]]
[[ booktable(cursor.fetchall()) ]]

[[-- 커서 종료 및 삭제 --]]
[[cursor.close()
del cursor
]]

[[-- 데이터베이스 연결종료 및 삭제--]]
[[objConn.close()
del objConn
]]
<예제10> 람다식을 이용한 데이터베이스 내용 출력

예제 10은 예제 9와 크게 다른건 없지만 테이블 표현이 람다식으로 빠져있기 때문에 람다식만 별도의 include 파일로 뺄 경우 람다식만 수정해도 템플릿을 쓰는 듯한 효과를 만들어 낼수도 있을 것이다.

그림7은 예제 9와 예10의 결과를 나타낸 화면이다. 두 화면 모두 결과가 동일하기 때문에 한 화면만 첨부한다.

(picture-spyce-database-list.png)
<그림7> 예제9와 예제10을 실행한 화면

지면을 조금 더 할애해서 pg 모듈을 사용해서 데이터를 출력하는 부분까지 다루고 싶지만 pg 모듈에 대한 이야기는 향후 세미나 또는 원고 게재가 있을때 조금 더 다뤄볼 수 있을 것이다.

마치며
많은 지면을 할애해서 파이썬에서의 db api 사용을 통한 간단한 웹 애플리케이션까지 알아보았다. 다음회에서는 이 연재의 마지막인 spyce와 cheetah 템플릿을 통한 사용방법과 도서목록 제작에 대해 알아볼 것이다. 마지막으로 궁금한 사항은 필자에게 언제든지 메일을 보내주면 친절하게 답변할 것을 약속한다.

2005/11/16

debian etch 에서 rpm 4.4 설치후 --initdb 시 에러날때

어렵게 구한 한소프트 리눅스용 한글 2005을 사용하려고 debian etch를 설치했는데
여기에 sid의 rpm 4.4 를 설치하고 --initdb 명령으로 rpmdb를 초기화 하는데 다음과 같은
에러가 발생했다.

rpmdb: unable to initialize mutex: Function not implemented
rpmdb: /var/lib/rpm/db.001: unable to initialize environment lock: Function not implemented
error: db4 error(38) from dbenv->open: Function not implemented
error: cannot open Packages index using db3 - Function not implemented (38)
error: cannot open Packages database in /var/lib/rpm
이경우 해결방법은 다음과 같다.

# cd /etc
# mkdir /etc/rpm
# %__dbi_cdb create cdb private mpool mp_mmapsize=16Mb mp_size=1Mb > /etc/rpm/macros

그리고 rpm 데이터베이스를 다음과 같이 재생성 하면 된다.(rpmdb 는 /var/lib/rpm에 위치한다고 가정한다)
# rpm --initdb /var/lib/rpm

참조 URL : http://uml.harlowhill.com/index.php/RebuildRPM

2005/11/11

힘들지?

힘들지? 상호야

있잖아, 니가 있기 때문에 내가 있고 내가 있기 때문에 니가 있는게
아닐까라는 생각을 자주 하게 돼.

상호야, 하나만 생각하렴.
길을 계속 걸어가렴. 너의 뒤엔 미래를 만들고 있는 내가 있어.
그리고 밝은 미래가 너를 기다리고 있어. 원하는 것... 바라는 것...
길을 계속 걸어가주렴

상호야, 주저 앉지말고 가줘...

내꿈은요..

내꿈은요. 그댈 향해서 가고 있는 자리에서
늘 행복해하는 그대의 모습을 바라보는 거랍니다.

지금은 서로 잘알지 못하지만 나도 힘낼꺼에요.
앞으로 얼마간의 시간이 있을지 모르겠지만 서로 힘내요~

늘 행복해하는 그대이기를...
................ So eun Lee...

glade에서 UI 디자인시 위젯 배치에 관해서.

리눅스에서 GUI 프로그램 개발은 여러 도구와 라이브러리가 사용될 수 있는데,
그중 하나는 GIMP 개발시 사용된 GTK의 Glade 도구이다.

Glade 에서 위젯을 배치하려면 hbox, vbox, table, fixed 도구를 사용하면 쉽고
빠르게 위젯을 배치할 수 있다.

2005/11/06

qmail에서 smtp-auth 시 checkpassword 사용에 관해서

오랫동안 리눅스 서버를 사용하면서 부딪치는 몇가지 문제에 대해서
골머리를 썩을때가 있다. 가장 난감할때가 바로 겪었던 문제를 어떠한 이유에서
다시 겪는건데, 지금 쓰는 건 그 해결책이다.

시스템 계정으로 smtp-auth시 checkpassword 를 사용할때..
pop3 인증 프로그램으로 checkpassword를 단순히 make 했을땐 아무런 문제없이
잘 인증되는데 반대로 smtp-auth만 사용하면 안되는 경우가 있다. 이 경우 문제점은
단 1가지다. checkpassword의 권한 문제이다.

smtp-auth시에는 왜 그런지 알 수 없지만 유저 인증을 하는 프로그램의 권한문제가
걸린다.


해결
checkpassword 프로그램의 소유자와 파일 권한을 수정한다. root 권한으로 수정한다.
# chmod 4110 /bin/checkpassword
# chown root.nofiles /bin/checkpassword

그리고 smtp-auth를 하면 문제없이 지나갈 것이다.

관련 url
http://www1.cuni.cz/~vhor/qmail/smtpauth-en.html

2005/11/02

대학은 꿈을 위해 가는 곳..

대학을 꿈을 위해 가는 곳이다.

나는 적어도 그렇게 생각하고 그렇게 살아왔다.
그런데 말이지. 왜 사람들은 명문대에 명문으로 뽑히는 학문을 하려할까?

나두 자유롭게 살고 싶다. 내가 가고 싶은 대학과 대학원
그리고 내가 만나고 싶은 사람, 내가 선택하고 싶은 사람.

뭐 이런것들 모두가 자유로운 삶의 일부겠지?

자 힘내자.

내가 다니고 있는 대학은 꿈을 위해 다니고 가는 곳이다!!