2005/12/29

요즘 연애부 기자들의 기억력은 새머리가 아닐까?

내가 좋아하는 연예인이 있어서 비교적 연예계 뉴스나 그 소식에
관심을 많이 갖는 편인데, 강수정 아나운서의 말 실수에 대해
어떤 기자가 기사를 썼는데 그이가 진행하는 강수정의 뮤직쇼(예전엔
김장훈의 뮤직쇼였다)가 방송하는 KBS 2FM인 Cool FM의 채널이
91.9Mhz 란다.

91.9Mhz는 수도권에서 MBC 표준 FM인데, 게다가 89.1Mhz.
Cool FM은 수도권이외에는 방송조차 안하는데 과연 이 연애부 기자는
글 쓸때 주파수 확인도 안하나? 하긴 기자보다 편집장이 더 문제지.

이러니까 우리나라 신문의 기사들이 항상 개판이지.

ㅋㅋ

2005/12/28

일일 드라마 보기

거참 드라마 보기 힘들다. 내가 한국에서 정말 첫째나 둘째 가라면 서러울 정도로
거의 모든 드라마의 등장인물과 스토리, 미리보기 내용을 꾀차는데

마침 오늘 오후 8시 25분에 시작하는 KBS1 일일 드라마 별난여자 별난남자를
보려고 KBS에서 로그인해서 OnAir를 가동했는데. 어랏

왜 드라마가 안 나오지. 뭔가 좀 이상했다. KBS2에서 뉴스 좀 보다가 방송
편성표를 보는 순간 느꼈다.

"앗 KBS2가 아니라 KBS1이었다 ㅡ.ㅡ"

한 12분 남은 상태에서 보기 시작했는데 역쉬, 드라마는 글자로 읽어대는 것보다
영상으로 보는게 최고다.

우헥. 그나저나 조엘은 아직도 내 신경을 박박 긁는걸.

원서 접수 안된게 교육부와 대학이 잘못한 말로만 외쳤던 교육혁신의 일환으로 볼 수 있나..

하루동안 대학에 원서 접수를 못하고 원수 접수 서버들이 다운당했다고 하는데
뉴스와 학부모들 학생들은 말로만 교육 혁신을 외치지 말고 서버 증설부터
하라고 하는데 그게 말이 되나.

하나. 원서접수 서버를 늘리면 되지 않냐고?
국내에서 원서 접수 회사는 총 3곳. 원서 접수는 매년 이 시기에만 집중적으로
이뤄질 뿐이고 그 이외의 기간에는 사실상 원서 접수가 거의 없다.
그런데 원서 접수 업체에 서버를 늘리라고? 매달 IDC에 나가는 비용은 어떻게 하라고?

둘. 원서 접수 업체는 대학에서 운영하지 않나?
대학들이 자기네들 돈 들여서 왜 남의 대학까지 원서 접수할 수 있는 시스템을 마련하겠나?

셋. IT 종사자들이 바보 같아서 그렇다고?
물론 시스템 설계가 엉성해서 그런일이 발생했다고 칩시다. 있을 수 있는 일이니까
그런데 왜 IT를 싸잡아서 비난할껀 뭐냐고? 몰려드는 사용자들을 어찌하라고?

결론. 그러니까 미리 어디갈지를 정해두던가. 대학놓고 저울질하면 우울한 세상밖에 더 만들어지겠나?

바보같은 한국인들 1편.(엇 그러고 보니 나도 한국인이네.. ㅋㅋ)

2005/12/27

조엘 온 소프트웨어

지금까지 나름대로 프로그래머라 항변하며 살아왔는데 내가 알고 지내는 한사람의
추천으로 읽게 된(순수하게 추천이었다) 조엘 온 소프트웨어는 지금 내 가치관을
뒤흔들고 있다.

뭐 정확하게 표현한다면 내가 없다고 해야 되나. 어쨌거나 지금 이 조엘이라는 작자는
내가 책을 보면서 가슴뛰는 감정을 느끼게 한 2번째 필자임에는 틀림없다.

1차는 누구냐고? 자바 개발자인 이창신씨다. 이창신씨는 아파치 자카르타 커미터로 활동하고 계시다.

이창신씨가 지은 자바 SDK 책이 이렇게 가슴뛰게 했었는데 오랜만에 귀한 진주를
만난 것 같다^^

다 읽으면 그대로 시행해 볼 수 있도록 노력해보자.

2005/12/22

답변형 게시판 알고리즘

어디에서나 흔히 볼 수 있는 웹 게시판 알고리즘이긴 하나 때때로 계속 만들기 귀찮아서 올려둔다.


idx family childLevel Subject
1 1 1 글 1
3 1 2 [RE] 글 1
6 1 3 [RE][RE] 글 1
5 1 4 [RE] 글 1
2 2 1 글 2
4 2 2 [RE] 글 2


다음과 같은 구조로 되어야 한다. 마지막에 올린 답글이 가장 최상위에 올라오게 된다.

새로운 글을 시작할 경우 family 값은 TABLE에서 max 값을 가져오고 childLevel은 1로 시작하게 된다.
이때 새로운 글에 답변이 달리면 자연이 childLevel의 값은 자기 부모글의 childLevel보다 1 높은 값을 지니게 된다. 이때 childLevel이 1인 부모글에 답글을 달게 되면 처음 작성된 답변글이 childLevel값이 나중에 달린 childLevel 값과 같아지게 되므로 누가 가장 먼저 나올지 며느리도 모른다.

따라서 이문제를 해결하기 위해선 마지막에 올린 답글이 가장 최상위에 올라와야 한다는 걸 생각하면 다음과 같은 방법으로 문제를 풀 수 있다.

table에 새로운 답변글을 하나 더 인서트하기 전에 html 폼에서 넘어온 family 값과 childLevel 의 값(이미 1이 더해진 값)을 받아서 table에 같은 family 값을 가지면서 childLevel보다 높은 값은 하나씩 더 하면 문제가 해결된다. 위의 알고리즘은 지금 설명한 내용을 기준으로 다음과 같은 형태를 지니게 된다.


idx family childLevel Subject
1 1 1 글 1
7 1 2 [RE] 글 1
3 1 3 [RE] 글 1
6 1 4 [RE][RE] 글 1
5 1 5 [RE] 글 1
2 2 1 글 2
4 2 2 [RE] 글 2


단지 이렇게 할 경우 글을 family와 childLevel의 값으로 asc 혹은 desc 정렬를 하면 순차적으로 값은 가져올 수 있으나 얼마나 칸을 띄워야 하는지 이것에 대한 판단 기준이 없으므로 이 부분에 대해선 조금 더 생각해볼 필요가 있다.

혹은 childLevel에 1이 더해진 값이 이미 존재할 경우 update 하지 않는 방법도 있을 것이나 글쎄.. 이건 조금 더 생각해 볼일이다.

2005/12/20

NeverSpam 적용을 위한 자바스크립트 및 Anchor

---> 이메일 확인을 위한 페이지(HTML)에 삽입(ex. 방명록 리스트, 게시판 세부 화면)
<script language="'javascript'">
function AntiSpam(id) {
window.open('./antispamin.php?UniqId='+id,'AntiSpam','width=180,height=263,left=1,top=1');
}
</script>

---> 이메일이 보였던 곳에 삽입(ex. 방명록 리스트 안의 실제 이메일 링크)
<a href="'javascript:AntiSpam($Id)'">추출방지</a>

/----------------------------------------------------------------
JavaScript 인자 id는 이메일이 있는 테이블(방명록 테이블)에서
넘어온 게시물을 확인시켜주고자 하는 것이다.
예) table description
id     name     subject                 email
1     이상호     소은씨만 봐요     search5@gmail.com

이라고 한다면 방명록 리스트에선 1이라는 id 값이 넘어올 것이다. 물론 이때의 1은 방명록
리스트에서 각 게시물의 고유한 아이디로서 다중 게시판을 사용할 경우 게시판 ID도 포함할 수 있으며 email 을 확인하기 위한 고유의 게시물 아이디등을 추가할 수 있다.
-----------------------------------------------------------------/

NeverSpam은 크게 2가지의 실행 방식을 제공하는데 gd 방식을 추천한다. exe 방식은 외부에 보안문제를 일으킬 수 있기 때문이다.

다중 보드일 경우 (gd)antispamin.php에 넘길 UniqID 값은 기본적으로 하나이며, 이 값에 추가로 덧붙이지 않고 다른 변수를 하나 더 추가해서 넘기고 (gd)antispamout.php에서 uniqid 는 신경쓰지 않고 $Email에 값을 집어넣는 곳에서는 UniqID 및 추가로 넘긴 값을 DB로 쿼리를 던져 값을 얻어온다.

네버스팸 프로그램은 http://www.neverspam.or.kr 에서 얻을 수 있다.

ps.. > 네버스팸은 아직까지도 베타이며 ASP, PHP, JSP, Perl 버전으로 제작되어 있다. 파이썬 버전이 없고, 프로그램은 구조화가 잘 되어 있지 않기 때문에 Class 를 이용하는 프로그램에선 면밀히 분석해서 클래스를 제작해서 구현해야 할 것이다. 나 역시 클래스 버전으로 재포팅을 생각해보고 있다.(이렇게 해서 쓰고 있는 라이브러리가 있다.)

네버스팸 프로그램에선 크게 5개의 함수와 중복된 함수(내용은 다르다) 2개가 있는데, 이중 4개의 함수는 공통적으로 쓰인다.
공통 함수명 : IpTest(), BlockIpRelease(), BlockIf(), BlockIpList()
(gd)antispamin.php 에서만 쓰는 함수명 : DelBmp()
중복 함수명 : Start()

클래스 제작시 Start 함수는 이름을 조금씩 바꿔 제작한다.

궁금한 사항은 search5@gmail.com 으로 메일 주세요~(근데 이거 관심가지고 있는 사람이 얼마나 될까..)

2005/12/19

PyGTK로 여러 화면 애플리케이션 작성 코드 sample(class)

데이터들은 사전으로 넘기면 될듯 하다. 인스톨러 제작하면서 시도해본다.
---
#!/usr/bin/env python

import pygtk
pygtk.require("2.0")
import gtk

class MultiWindow1:
    def btNext(self, widget, data=None):
        window2 = MultiWindow2()
        self.window1.hide()

    def __init__(self):
        self.window1 = gtk.Window(gtk.WINDOW_TOPLEVEL)
        button = gtk.Button("Next")
        button.connect("clicked", self.btNext)
        self.window1.add(button)
        button.show()

        self.window1.connect("destroy", lambda w: gtk.main_quit())
        self.window1.show()


class MultiWindow2:
    def btPrev(self, widget, data=None):
        window2 = MultiWindow1()
        self.window.hide()

    def __init__(self):
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        button = gtk.Button("Prev")
        button.connect("clicked", self.btPrev)
        self.window.add(button)
        button.show()

        self.window.connect("destroy", lambda w: gtk.main_quit())
        self.window.show()

def main():
    gtk.main()
    return 0

if __name__ == "__main__":
    MultiWindow1()
    main()

PyGTK로 여러 화면 애플리케이션 작성 코드 sample(non-class)

가장 첫번째 줄은 리눅스 등의 유닉스 아류작에서만 사용된다.
---
#!/usr/bin/env python

import pygtk
pygtk.require("2.0")
import gtk

def window_show(widget, data=None):
    window2 = gtk.Window(gtk.WINDOW_TOPLEVEL)
    window2.connect("destroy", lambda w: gtk.main_quit())
    button = gtk.Button("이전")
    button.connect("clicked", window_hide, window2, data)
    window2.add(button)
    button.show()
    window2.show()
    data.hide()

def window_hide(widget, data=None, data2=None):
    data2.show()
    data.hide()

window1 = gtk.Window(gtk.WINDOW_TOPLEVEL)
button = gtk.Button("다음")
button.connect("clicked", window_show, window1)
window1.add(button)
button.show()
window1.connect("destroy", lambda w: gtk.main_quit())
window1.show()

gtk.main()

방송대 교가에 빠져보시게나..

내가 다니는 학교지만 여태까지 교가가 어떻게 생겨먹었는지도 몰랐는데.
웃기다~~

ㅋㅋㅋ
한번 들어들 보셔요.
방송대학교 교가

악보

믿어? 믿지 않아?

동시대의 사람들이 자주 쓰는 말이 어떤 것이 있을까? 지난 토요일 늦은 7시에 친구들을
만났다.

뭐.. 이 녀석들 말로만 친구지.. 연락은 지네들끼리 하질않나.. 게시판에 글 남기라면 남기지도
않지.. 너무하는 것들 아냐.

뭐 그런 녀석들이래도 어쩔 수 없다. 같이 초등학교 나와놓고서 딴말할 수 없는 것 아닌가?
가만.. 그날 누가 나왔었지..

김복래, 김현숙, 서지명, 박득규, 송권호, 김한중, 은현준, 이경치, 안병찬, 나~

그래 이렇게 나왔었네.. 다들 오랜만에 보는거라서.. 수다도 많이 떨줄 알았는데.. 역시나더군..
어떻게 새벽 4시까지 수다를 떠냐. 이것들아

물론 나야.. 몇마디에서 멈췄다.. 우헥... 니가 그래놓고도 천하의 수다쟁이란 말야??(사실 난 수다쟁이가 아니다)

그건 그렇구.. 오랜만에 본 복래는 9급 공무원이 되었고.. 득규는 카센터에 있고.. 권호는 하이닉스 다니고.. 한중이는 KT 인터넷 관리팀에 있고.. 병찬이는.. 해경이 될 몸이시고..

하긴 이 나이쯤 되면 다들 어느정도 자리잡을때가 되었지(내 나이는 24..)
나도 남들처럼 군대를 제대했어야 했는데. 너무 귀찮았다 ㅡ.ㅡ;;;

아무튼.. 오늘도 늘.. 행복한 시간...

ps... 미움..그리움..행복함..사랑해... 지금부터야. 가자!! 미래로.

2005/12/12

이소은 4집 애인..

한번 들으면 슬픈 멜로디로 나의 감정을 적셔오는 노래다. 언제부터인지
소은씨의 노래는 늘.. 내 감정에 살아 숨쉬고 있는 느낌이다^^

--
헤어진지 꽤나 오래됐는데 아직도 누가 내게 물으면
애인있다 하죠
사랑하는 사랑이 애인이잖아
내곁에 머무르지 않아도 애인인거잖아
나혼자 걸어도 나 혼자 웃어도
니가 곁에 있는 듯이 그렇게 생각해

내마음이 너를 놓치 못하는 걸
아직도 그 자리에 남아서
맴돌고 있는걸

우리다시 그 어떤 예쁜 기억도
만들수 없다는 거 알지만 그래도 괜찮아
눈을 감고 니 어깨에 기대울던
따뜻한 지난 겨울 만으로 웃을 수 있는걸

나혼자 걸어도 나 혼자 웃어도
니가 곁에 있는 듯이 그렇게 생각해

내 마음은 너를 버릴 수 없어
너를 잊어버리려 하지만 그럴 수가 없어

그럴 수가 없어

주말의 기말시험..

학교를 벌써 5년째 다니고 있다.. 사실 군대를 연기하기 위해서
다니는 거라서 학점엔 그다지 신경쓰고 있지 않지만 이제 관리의 필요성을
느끼고 있다.

쌍권총의 압박이라고 해야 할까?? 가히 쌍권총의 압박은 도대체 매해 이러니
살맛이 안나기도 할려고 한다. 그건 그렇고

주말에 갑작스레 변경된 시험장소로 향했다. 원래 학교는 한양대 앞에 있는
덕수정보산업고등학교. 그런데 무슨 일인지 시험 며칠전에 성동여자실업고등학교로
바뀌어 버린탓에 적응을 못하고 있었다..(머리가 요즘 아프다)

시험일인 11일 오전 9:40가 넘어서야 일어난 난 아뿔사를 외치며, "아 이게 아니야"
라는 소리를 연발하기 시작했다. 다음 시험 시간이 10:30분 부터 였기 때문에 급했다.

허겁지겁 씻는둥 마는 둥 학교 차를 몰고 시험장으로 향했다. 어떻게 잘 도착하고
주차도 문제없이 끝내고 교실을 막 찾아 들어갔더니 바로 시험.. 으악....

공부를 못했으니 성적이 안나오리나는 건 당연지사가 아닐까나.

시험 과목 자체가 1, 2학년껄 보다보니 오전, 오후에 두루 걸쳐 있었다.

결과적으로 플래너에 시험시간에 늦지 않게 준비하자는 빈 말이 되어버렸다. 이에는 내가
한게으름하는 탓도 있었지만 우리학교 전산 시스템이 모조리 activex 를 사용해 버리는 탓에
리눅스를 사용하는 내가 접속할 수 없었다.

참 아쉬운 일이 아닐 수 없었지만 그냥 참기로 했다. 내가 신도 아니고...

정오에 간단하게 식사를 챙겨먹고 교재를 가져가지 않고 가져온 PyGTK 튜토리얼을
뚫어지게 시험보는 내내 빈 시간때마다 챙겨보기 시작했다. 내 장점은 여기에 있는
거겠지만..

그렇게 1과목을 놓친 5과목을 보는 둥 마는 둥 하고 나오고 같은 장소는 아니지만 대학
동기 누나를 만나 책 사고 밥 먹고 나왔다.

그러고 보니 종로 영풍문고는 15분당 500원이라는 아주 저렴한 주차비였었다.
담에 종로 갈일 생기면 영풍빌딩에 묶어나야 겠다.(근데 종로까지 차를 타고 납실일이 있을까?)

오늘도 분주하게 시작한 하루. 성과있는 하루를 만들어내기 위해 노력하자!

2005/12/09

ldconfig에서 에러나면??

회사에서 쓰고 있는 데비안 리눅스에서 다음과같은 에러가 발생하였다.

# apt-get dist-upgrade
...
Setting up zlib1g (1.2.2-4.sarge.2) ...
ldconfig: Writting of cache data failed: No space left on device
dpkg: error processing zlib1g (--configure):
subprocess post-installation script returned error exit status 1
Error were encountered while processing:
zlib1g

여기에서 보이는 바와 같은 에러는 / 파티션이 100% 다 썼을때 나타나는 현상이다.
해결하려면 / 파티션의 공간을 넓혀주어야 하나 LVM이 아닌경우엔 다시 설치해야 하는
치명타가 있다.

--원문
That's most likely because your root partition (/) is full, and it's
trying to write to the /etc directory - which is included in your root
partition.

You could either delete something you don't need on the root partition
to give yourelf some wiggle room (as previously mentioned), or you could
consider adding some disk space to the root partition by resizing it.
Looks like you have plenty of elbow room on the drive (especially in
your /home partition) to do the resizing.

You can get a better look at your overall partition layout by running
'fdisk -l /dev/hda' (as root), and you can get the output into a text
file with 'fdisk -l /dev/hda > filename'

정말 어이없다.. 리눅스 또 깔아야 하다니.. 지겹다..

2005/12/08

아름다운 생각

명언은 책에서만 발견할 수 있는 게 아니야.
일상 생활속에서 가장 가까이 찾을 수 있는 있는 것 같아 그치?

아깝다!

그 동안 잊혀진 많은 생각들.
다 적어놓을 걸.

평범한 사람들의 생각과 이야기가
세상을 돌게 만든다.

너무 아름답다!!!

고맙습니다~~내 주위의 모든 분들!
나를 이렇게 키워 주셔서.^^

2005.09.06 http://cyworld.com/serealm 소은씨 홈피 다이어리에서...

2005/12/06

KDE에서 gtk1 프로그램을 읽어들일때 폰트가 깨지면??

나는 데비안에서 KDE3 을 사용하는데 gtk1 어플리케이션인
xmms와 glimmer 를 사용하는데 이때 프로그램이 로드되면 설정창이나
기타 한글을 보여주는 부분이 모두 깨지게 된다.

문제는 gnome을 세션으로 띄우면 이런 문제는 발생하지 않는 다는 건데
이 문제를 해결하기 위해선 홈디렉토리에서 다음과 같은 작업을 하면 된다.

$ cp .gtkrc-1.2-gnome .gtkrc

이 문제가 발생하는 이유는 KDE에서는 .gtkrc-1.2-gnome을 읽어들이지 않고
.gtkrc 를 읽어들이기 때문에 발생하는 것이다(KDE에 버그 보고를 해야 하는 사항)

그리고 파일에서 읽어들이는 파일인 .gtkrc.mine 파일은 미리 만들어져 있어야 한다.

웹에서의 다중 플랫폼 정보 접근성 이야기

어디서부터 이야기 보따리를 풀어내야 할까? 웹은 오래전부터 정보 접근성을 누구에게나 개방했었다.

그런데 웹이 무르익기도 전에 네스케이프(http://www.netscape.com)는 웹의 주도권을 놓고 독주하기 시작하면서 브라우저에 자체의 기능을 넣고 질주를 계속하다 새 제품의 출시 이유로 MS의 IE에게 브라우저의 왕자 자리를 넘겨주게 되었다.

하지만 IE는 웹의 표준을 마음대로 무시했으며 심지어 IE가 질주하는 동안에 많은 애플리케이션 업체들은 IE 자체에 먹는 테크닉과 MS Windows에만 이식되는 기술을 개발하기에 이르게 되었다.

우리가 다이나믹 HTML이라 부르는 그 기술들이 사실은 브라우저와 OS에 의존적이라는 것이다. 물론 사용자의 웹 브라우징을 편리하게 다루는데 있어서 MS의 Active X 기술에 제동을 걸 필요는 없다.

하 지만 내가 Active X에 제동을 걸고자 하는 건 다른 이유에서다. 바로 정보 접근성이라는 건데, MS는 아직까지도 모질라 프로젝트가 밀고있는 Cross Platform 기술인 XPCOM을 무시하고 있다는 거다. 그 덕분에 수많은 리눅스와 맥 유저들은 많은 은행들에 인터넷 뱅킹을 하지 못하게 되었다.

나만 해도 인터넷 뱅킹을 할려고 윈도우를 가끔 킨다. 근데 이러한 브라우저와 운영체제에 의존적인 기술이 은행에만 도입된 것은 아니라는 거다. 그럼 어디에 도입되었냐고?

국가 교육기관인 한국방송통신대학교, 국가 전자 정부 사이트, 국가 과학 도서관 등 수많은 정부 부처 및 국가 기관들이다.

이들 기관은 윈도우가 아니면 그 어떠한 혜택을 누릴 수 없다. 물론 여기에 그 기관들을 나열한다는 건 어려운 일일뿐더러 그렇게 해서 얻어질 수 있는 혜택은 많지 않다.

그럼 왜 이처럼 우리에게 웹에서의 정보 접근성은 차단되어 있는 것일까? 답은 하나다. 정보 접근성은 우리 스스로가 찾지 않으려 했다는 것이다.

물론 1차적으로 물었을때가 답이지만 2차적으로는 국가 IT를 책임지는 정보통신부와 그 외 기관이 넉을 놓고 윈도우가 독점하는 꼴을 바라봤다는 거다.

리눅스가 성장하기에 앞서 수 많은 브라우저가 공통으로 제공하는 Cross Platform 기술을 사용했더라면 이런일은 없었을텐데 아쉬운 부분이다.

정보접근성. 머지 않은 날에 해결되겠지만 소수의 유저가 모든 웹 사이트에 자유로이 드나들며 밝게 웃을 수 있는 날이 언제쯤 올까?

리눅스에서 Umask 설정에 관해서

리눅스에서 Umask 를 사용할땐 주의해야 한다.

기본적으로 umask을 이용해 파일이 생성될땐 허가권의 반대로 설정을 하게 된다.
설정 확인은 다음과 같이 한다.

$ umask -S

출력결과 : u=rw,g=rwx,o=rwx

물론 위의 결과대로라면 다음과 같은 권한을 가진 파일이 만들어져야 한다.

-rw-rwxrwx 1 shlee shlee 0 2005-12-06 19:00 1

퍼미션에 대한 자세한 설명은 유닉스 퍼미션에 관한 서적이나 내용을 참조하기 바란다.

그런데 파일을 만들면 다음과 같은 파일이 만들어진다.

-rw-rw-rw- 1 shlee shlee 0 2005-12-06 20:01 4

그 이유는 기본적으로 셸이 파일을 만들땐 777 mask를 가지지 않고 0666 이라는 마스크를 가지기
때문이다.

이 때문에 다음과 같은 공식이 성립한다.
0666 & ~022 = 0644 = rw-r--r--

박스1 : 022는 umask의 기본값이다.

그때문에 기본값인 022은 666에서 022을 뺀 결과인 644(-rw-r--r--)을 가지게 된다.

처음엔 파이썬 공부를 하다가 일일이 chmod로 권한을 조정하는게 귀찮아서 조금 건드려보다가
알게된 사실인데, 혹시 까먹을까 두려워서 적어둔다.

새로운 친구들

지난 친구의 결혼식에서 새로운 친구들을 만났다.

늘 아쉬움에 뒤를 돌아보곤 했는데, 새로운 친구들은 곁에서
보이는 이상의 의미를 다시한번 깨쳐주었다.

언제부터였을까.. 친구라는 존재를 만들지 않게 된 것이
사람에 속은것이 유독 있어서 였던 걸까? 아니면 왜 그랬던 걸까?

친구의 결혼식에서 다시만난 고교 동기와 친구의 중학교 동기인
선화, 재인씨, 경숙씨
아직은 익숙치 않은 사이지만 조금 더 나아지겠지?

세 친구들에게 내가 부탁 하나만 한다면,
지금도 앞으로 좋은 사이가 되길 바랍니다.

-꿈의 끝자락을 늘어잡고 있는... 내가..

2005/12/05

불멸의 이순신을 초등학교 버전으로 만들었다고 하넹..


우리나라 전쟁사에 있어서 7년동안 22번인가? 23번을 싸워서 단 한번도 진적이 없는 장수는 이순신 밖에 없을것이다.. 그러한 이순신과 그 부하들을 초등학교 버전으로 만들어서 퍼왔으니 즐겁게 감상하기를..

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 템플릿을 통한 사용방법과 도서목록 제작에 대해 알아볼 것이다. 마지막으로 궁금한 사항은 필자에게 언제든지 메일을 보내주면 친절하게 답변할 것을 약속한다.