<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
	<channel>
		<title>greenfish blog</title>
		<link>http://greenfishblog.tistory.com/</link>
		<description>초록생선의 블로그 입니다. 많은 정보를 함께 공유해요.</description>
		<language>ko</language>
		<pubDate>Wed, 16 May 2012 07:58:57 +0900</pubDate>
		<generator>Tistory 1.1 (http://www.tistory.com/)</generator>
		<managingEditor>초록생선</managingEditor>
		<image>
			<title>greenfish blog</title>
			<url>http://cfile3.uf.tistory.com/image/12478B124AA9925028C2BC</url>
			<link>http://greenfishblog.tistory.com</link>
			<description>초록생선의 블로그 입니다. 많은 정보를 함께 공유해요.</description>
		</image>
		<item>
			<title>PE 포맷 바이너리 파일의 버전을 구하는 함수</title>
			<link>http://greenfishblog.tistory.com/127</link>
			<description>&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile8.uf.tistory.com/original/195DCB474F9DCFB1207854&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile8.uf.tistory.com/image/195DCB474F9DCFB1207854&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;001.png&quot; height=&quot;466&quot; width=&quot;425&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
와 같이 fileversion을 구하는 함수를 공유합니다.&lt;br /&gt;
fileversion은 숫자가 4개로 구성되는데, 각 숫자값을 전달해 줍니다.&lt;br /&gt;
&lt;/P&gt;&lt;PRE class=c++ name=&quot;code&quot;&gt;// version.lib import
#include &amp;lt;assert.h&amp;gt;
#include &amp;lt;winver.h&amp;gt;

DWORD GetVersion(IN LPCTSTR lpszFilePath, OUT PWORD pwVer1, OUT PWORD pwVer2, OUT PWORD pwVer3, OUT PWORD pwVer4)
{
	DWORD				dwRtnValue				= ERROR_SUCCESS;
	DWORD				dwHandle				= 0;
	DWORD				dwDataSize				= 0;
	LPBYTE				bufVersionData			= NULL;
	TCHAR				szValue[MAX_PATH]		= {0,};
	LPVOID				pData					= NULL;
	UINT				nQuerySize				= 0;
	VS_FIXEDFILEINFO*	pVsffi					= NULL;

	if ((NULL == lpszFilePath) || (NULL == pwVer1) || (NULL == pwVer2) || (NULL == pwVer3) || (NULL == pwVer4))
	{
		dwRtnValue = ERROR_INVALID_PARAMETER;
		assert(FALSE);
		goto FINAL;
	}

	// Clear output
	*pwVer1 = 0;
	*pwVer2 = 0;
	*pwVer3 = 0;
	*pwVer4 = 0;

	dwDataSize = ::GetFileVersionInfoSize(lpszFilePath, &amp;amp;dwHandle);
	if (0 == dwDataSize)
	{
		dwRtnValue = ::GetLastError();
		assert(FALSE);
		goto FINAL;
	}

	bufVersionData = new BYTE[dwDataSize];
	if (NULL == bufVersionData)
	{
		dwRtnValue = ERROR_NOT_ENOUGH_MEMORY;
		assert(FALSE);
		goto FINAL;
	}
	ZeroMemory(bufVersionData, sizeof(BYTE)*dwDataSize);

	if (FALSE == ::GetFileVersionInfo(lpszFilePath, 
									  dwHandle, 
									  dwDataSize, 
									  bufVersionData))
	{
		dwRtnValue = ::GetLastError();
		assert(FALSE);
		goto FINAL;
	}

	if (FALSE == ::VerQueryValue(bufVersionData, 
								 TEXT(&quot;\\&quot;), 
								 (LPVOID*)&amp;amp;pVsffi, 
								 &amp;amp;nQuerySize))
	{
		dwRtnValue = ::GetLastError();
		assert(FALSE);
		goto FINAL;
	}

	*pwVer1 = HIWORD(pVsffi-&amp;gt;dwFileVersionMS);
	*pwVer2 = LOWORD(pVsffi-&amp;gt;dwFileVersionMS);
	*pwVer3 = HIWORD(pVsffi-&amp;gt;dwFileVersionLS);
	*pwVer4 = LOWORD(pVsffi-&amp;gt;dwFileVersionLS);

FINAL:

	if (NULL != bufVersionData)
	{
		delete [] bufVersionData;
		bufVersionData = NULL;
	}

	return dwRtnValue;
}
&lt;/PRE&gt;&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-127-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-127-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=28646796&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/127&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/프로그래밍&quot;&gt;프로그래밍&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/프로그래밍/Let%27s%20Share%20it&quot;&gt;Let's Share it&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/127&quot; &gt;PE 포맷 바이너리 파일의 버전을 구하는 함수&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/118&quot; &gt;프로세스 생성 종결자 (ShellExecute / CreateProcess)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/117&quot; &gt;손쉽게 File을 나열할 수 있는 class 공유(FindFirstFile/FindNextFile Wrapper)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/116&quot; &gt;VC9.0에서 crypto++ library를 이용하여 SHA256(sha2) 구하기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/12/14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/115&quot; &gt;비동기(OVERLAPPED I/O, IOCP, Thread Pool) IPC PIPE Class 공유&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/12/14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/114&quot; &gt;[ATL/MFC/C++] Ini Parser(ini 파서)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/11/30&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>Let's Share it</category>
			<category>GetFileVersionInfo</category>
			<category>GetFileVersionInfoSize</category>
			<category>VerQueryValue</category>
			<category>버전</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/127</guid>
			<comments>http://greenfishblog.tistory.com/127#entry127comment</comments>
			<pubDate>Mon, 30 Apr 2012 08:39:02 +0900</pubDate>
		</item>
		<item>
			<title>[06] django admin site</title>
			<link>http://greenfishblog.tistory.com/126</link>
			<description>&lt;P&gt;참고 : &lt;A href=&quot;http://www.djangobook.com/en/2.0/chapter06/&quot;&gt;http://www.djangobook.com/en/2.0/chapter06/&lt;/A&gt;&lt;br /&gt;
&lt;br /&gt;web site의 특정 계층을 위한 &lt;EM&gt;admin interface(관리자 인터페이스)&lt;/EM&gt;는 infrastructure의 필수 부분으로 자리잡았다. 이는 web 기반의 interface이고, 신뢰된 site 관리자로 제한하며, 그는 site content를 추가, 편집 그리고 삭제가 가능하다. 몇몇 일반적인 예로, blog에 글을 post 할때 쓰이는 interface,&amp;nbsp;적절한 사용자 생성의 댓글을 사용하는데 쓰이는 백엔드 site 관리자, 그리고 당신의 고객이 생성한 web site를 릴리즈 업데이트하는데 사용되는 도구등이 해당된다.&lt;br /&gt;
&lt;br /&gt;admin interface는 만드는데 지루하다는 문제가 있다. web 개발은 공개적인 기능을 개발할 때 즐거운데, admin interface는 늘 같은 내용이다. 사용자 인증, form을 표시하고 처리하기, 입력 검증, 기타 등등을 해야 한다. 이는 지겹고 반복적이다.&lt;br /&gt;
&lt;br /&gt;그래서 django에서는 이러한 지루하고 반복잡업에 대해 어떻게 접근할까? 단지 두세줄의 code 혹은 없이도 가능하게 한다. django로 admin interface를 만드는것은 해결된 문제이다.&lt;br /&gt;
&lt;br /&gt;본 장은 django의 자동 admin interface에 대해 다루기로 한다. model에 있는 metadata를 읽어 기능이 동작하게 되는데, 이는 site 관리자가 즉각 시작할 수 있는 강력하고 생산성이 준비된 interface를 제공하기 위함이다.&amp;nbsp; 여기서 우리는 이 기능을 어떻게 활성화, 사용, 그리고 커스텀할지를 알려준다.&lt;br /&gt;
&lt;br /&gt;우리는 당신이 django의 admin site를 사용하지 않더라도 본 chapter를 읽기를 권장한다. 왜냐하면, admin-site 사용법과 상관없이 django의 모든것을 적용할 수 있는 몇몇 개념이 소개되기 때문이다.&lt;br /&gt;
&lt;br /&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;django.contrib package&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;br /&gt;
&lt;br /&gt;django의 자동 admin은 django.contrib이라 불리는 django 기능의 한 부분인데, 이는 code framework에 많은 유용한 add-on이 포함되어 있다. django.contrib을 python 표준 라이브러리와 동일하게 생각하면 된다. 당신의 application에서 다시 개발할 필요가 없도록 django에서 묶어놓은 것이다.&lt;br /&gt;
&lt;br /&gt;admin site는 django.contrib의 첫 부분인데, 이 책에서 다루고 있다. 기술적으로 django.contrib.admin으로 불려진다. django.contrib의 다른 가능한 기능은 사용자 인증 시스템(django.contrib.auth), 세션 지원(django.contrib.sessions), 그리고 사용자 코멘트(django.contrib.comments)등을 지원한다. 다양한 django.contrib 기능을 알고 있다는것은 당신을 django 전문가로 만들게 할 것이고, chapter 16에서 자세히 설명할 것이다. 지금은 django는 많은 훌륭한 add-on이 있고, 그들은 django.contrib에 있다는 것만 알고 있자.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;admin interface 활성화 하기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;django admin site는 옵션사항인데, 단지 몇개의 특정 종류의 site만 사용하기 때문이다. 이는 당신 project에 그것을 활성화하는데 단지 몇개의 과정만 필요하다는것을 의미한다.&lt;br /&gt;
&lt;br /&gt;처음으로, setting 파일에 다음 사항을 반영한다.&lt;/P&gt;
&lt;OL style=&quot;LIST-STYLE-TYPE: decimal&quot;&gt;
&lt;LI&gt;INSTALLED_APPS에 'django.contrib.admin'를 추가한다. (추가할때, 그 순서는 중요하지 않으나, 알파벳 순서를 지키는것이 가독성에 좋다.)&lt;/LI&gt;
&lt;LI&gt;INSTALLED_APPS에 'django.contrib.auth', 'django.contrib.contenttypes', 그리고 'django.contrib.sessions'가 있는지 확인한다. django admin site는 이 3개의 package를 필요로한다.&lt;br /&gt;
(이후에 설명될 &quot;admin site에 model 추가하기&quot;를 위해 'mysite.books'가 필요할 지 모른다)&lt;/LI&gt;
&lt;LI&gt;MIDDLEWARE_CLASSES에 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', &lt;br /&gt;
'django.contrib.auth.middleware.AuthenticationMiddleware',&lt;br /&gt;
'django.contrib.messages.middleware.MessageMiddleware'가 있는지 확인한다.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;settings.py는 대략 아래와 같을 것이다.&lt;PRE class=python name=&quot;code&quot;&gt;...
MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    # Uncomment the next line for simple clickjacking protection:
    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
...
INSTALLED_APPS = (
	'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
	
    #'django.contrib.sites',
    #'django.contrib.messages',
    #'django.contrib.staticfiles',
    # Uncomment the next line to enable the admin:
    #'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',&lt;/PRE&gt;&lt;PRE class=python name=&quot;code&quot;&gt;    # 아래 &quot;admin site에 model 추가하기&quot;에 의해 추가됨 
    #'mysite.books'
)
...&lt;/PRE&gt;&lt;br /&gt;
두번째로 &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;syncdb&lt;/STRONG&gt;&lt;/FONT&gt;를 실행한다. 이 step은 admin interface가 사용할 database table을 추가적으로 설치한다. syncdb를 INSTALLED_APPS에 있는 'django.contrib.auth'로 실행하면 superuser 생성에 대해 질문을 받게 된다. 만약 이를 수행하지 않는다면, admin user 계정을 생성하기 위해 &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;createsuperuser&lt;/STRONG&gt;&lt;/FONT&gt;를 실행해야 한다. 그렇지 안핟면, admin site에 로그인할 수 없다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\mydjango\mysite&amp;gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;syncdb&lt;/STRONG&gt;&lt;/FONT&gt;&lt;br /&gt;
Creating tables ...&lt;br /&gt;
Creating table django_admin_log&lt;br /&gt;
Creating table auth_permission&lt;br /&gt;
Creating table auth_group_permissions&lt;br /&gt;
Creating table auth_group&lt;br /&gt;
Creating table auth_user_user_permissions&lt;br /&gt;
Creating table auth_user_groups&lt;br /&gt;
Creating table auth_user&lt;br /&gt;
Creating table django_content_type&lt;br /&gt;
Creating table django_session&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;You just installed Django's auth system, which means you don't have any superuse&lt;br /&gt;
rs defined.&lt;br /&gt;
Would you like to create one now? (yes/no): &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;y&lt;br /&gt;
&lt;/STRONG&gt;&lt;/FONT&gt;Please enter either &quot;yes&quot; or &quot;no&quot;: &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;yes&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
Username (leave blank to use 'administrator'): &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;greenfish&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
E-mail address: &lt;/FONT&gt;&lt;A href=&quot;mailto:foo@bar.com&quot;&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;foo@bar.com&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;br /&gt;
&lt;FONT color=#ffffff&gt;Password:&lt;br /&gt;
Password (again):&lt;br /&gt;
Superuser created successfully.&lt;br /&gt;
Installing custom SQL ...&lt;br /&gt;
Installing indexes ...&lt;br /&gt;
Installed 0 object(s) from 0 fixture(s)&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\mydjango\mysite&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;
세번째로, URLconf(urls.py)에 admin site를 추가한다. 디폴트로 &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;django-admin.py&lt;/STRONG&gt; &lt;STRONG&gt;startproject&lt;/STRONG&gt;&lt;/FONT&gt;는 django admin을 위해 주석 처리한 code가 있다, 그리고, 이를 주석 해제하면 된다. 다음과 같이 수정한다. 
&lt;P&gt;&lt;/P&gt;&lt;PRE class=python name=&quot;code&quot;&gt;from django.conf.urls import patterns, include, url

# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
...
    # Uncomment the next line to enable the admin:
    url(r'^admin/', include(admin.site.urls)),
...
)&lt;/PRE&gt;위 설정의 일부로 django의 admin site를 볼 수 있다. &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;runserver&lt;/STRONG&gt;&lt;/FONT&gt;를 실행한뒤, &lt;A href=&quot;http://127.0.0.1:8000/admin/&quot;&gt;http://127.0.0.1:8000/admin/&lt;/A&gt;에 들어가 보면 된다.&lt;br /&gt;

&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;br /&gt;
&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;admin site 이용하기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;admin site는 기술자가 아닌 사람들에의해 사용될 것을 예상하여 설계되었다. 그럼에도 불구하고 기초적인 기능은 익히는것이 좋다.&lt;br /&gt;
&lt;br /&gt;처음 들어가보면, 아래와 같이 로그인화면을 볼 수 있다.&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile25.uf.tistory.com/original/1307CE4F4F9E42962FA4EF&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile25.uf.tistory.com/image/1307CE4F4F9E42962FA4EF&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;001.png&quot; height=&quot;326&quot; width=&quot;441&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;username과 password로 로그인하면 superuser를 추가한 것이다. 만약 로그인할 수 없다면, 이미 superuser를 생성을 확인해 봐야 한다. &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;createsuperuser&lt;/STRONG&gt;&lt;/FONT&gt;를 실행해 보기 바란다.&lt;br /&gt;
&lt;br /&gt;일단 로그인하였다면, admin 홈페이지를 보게될 것이다. 이 page는 admin site에서 편집할 수 있는 모든 종류의data를 나열한다. 이때, 아직 model을 활성화하지 않았기 때문에, 목록은 비어있다. 단지 Groups and Users만 있는데, 이는 기본으로 포함된 편집가능한 model들이다.&lt;br /&gt;
&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile8.uf.tistory.com/original/1906EF464F9E45BE34EC00&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile8.uf.tistory.com/image/1906EF464F9E45BE34EC00&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;002.png&quot; height=&quot;162&quot; width=&quot;620&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;django admin site에 있는&amp;nbsp;data의 각&amp;nbsp;type은 &lt;EM&gt;변경 내역(change list)&lt;/EM&gt;과 &lt;EM&gt;편집창(edit form)&lt;/EM&gt;을 가진다.&amp;nbsp;change list는 database에 있는 모든 가능한 object를 보여주고, edit form은&amp;nbsp;database에 있는 특정 record에 대한&amp;nbsp;추가/변경/삭제를 가능하게&amp;nbsp;한다.&lt;br /&gt;
&lt;br /&gt;(Note : admin-site의 언어 선택은 추후 chapter 19에서 다룬다)&lt;br /&gt;
&lt;br /&gt;&quot;Users&quot;에 있는 &quot;Change&quot; 링크를 선택하면, user에 대한 변경사항을 보여준다.&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile24.uf.tistory.com/original/187B103A4FA07B05284D1C&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile24.uf.tistory.com/image/187B103A4FA07B05284D1C&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;003.png&quot; height=&quot;351&quot; width=&quot;620&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
이 page는 database의 모든 사용자를 나열한다. SELECT * FROM auth_user; SQL query문에 대한 web 버전이라고 생각하면 된다. 만약 이후에 진행될 예제를 통해 사용자 추가등을 실행했다면, 더만은 user를 보게될 것이고 필터링, 정렬 그리고 검색등을 수행할 수 있다.&lt;br /&gt;
&lt;br /&gt;당신이 추가했던 username(여기서는&amp;nbsp; greenfish)를 선택하면, 다음과 같은 edit form을 보게 된다.&lt;br /&gt;
&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile7.uf.tistory.com/original/127E76394FA07CD2271EC5&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile7.uf.tistory.com/image/127E76394FA07CD2271EC5&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;004.png&quot; height=&quot;701&quot; width=&quot;588&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile23.uf.tistory.com/original/147B103A4FA07D69313C0A&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile23.uf.tistory.com/image/147B103A4FA07D69313C0A&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;005.png&quot; height=&quot;791&quot; width=&quot;588&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
이 page는 user의 속성(성, 이름, 기타 권한등등)을 변경하도록 해준다. 또다른 주요 사항으로는 다른 type의 field는 다른 위젯으로 나타난다는 것인데, 예를 들어, date/time field는 calendar control, boolean field는 checkbox, character field는 간단한 text input으로 구성되어 있다.&lt;br /&gt;
&lt;br /&gt;화면 하단의 delete button을 통해 record를 삭제할 수 있다. 이는 다시 확인창을 발생시키는데, 함께 삭제되는 의존성이 있는 object도 표기된다. 예를 들어, publisher를 삭제한다면, publisher를 가진 모든 book은 함께 사제될 것이다.&lt;br /&gt;
&lt;br /&gt;&quot;Add&quot; button을 통해 record를 추가할 수 있다. 이는 당신이 값을 채워 넣어야할 내용을 비워서 보여준다.&lt;br /&gt;
&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile7.uf.tistory.com/original/124E8A474FA08E471B27AD&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile7.uf.tistory.com/image/124E8A474FA08E471B27AD&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;006.png&quot; height=&quot;407&quot; width=&quot;582&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
당신이 입력한 값에 대한 검증또한 수행해 준다. 필수 항목을 누락한채 저장하려면 다음과 같은 오류창이 발생한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile22.uf.tistory.com/original/125F014A4FA08ED417363E&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile22.uf.tistory.com/image/125F014A4FA08ED417363E&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;007.png&quot; height=&quot;488&quot; width=&quot;584&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
만약 기존에 있는 object를 편집했다면, History link를 실행할 수 있다. admin interface를 통한 변경은 저장되며 History link를 통해 확인할 수 있다.&lt;br /&gt;
만약 user의 e-mail을 수정했으면,&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile23.uf.tistory.com/original/134AF63B4FA094F52C9223&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile23.uf.tistory.com/image/134AF63B4FA094F52C9223&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;008.png&quot; height=&quot;330&quot; width=&quot;455&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
와 같이 되고, 그에 따른 History는 다음과 같다.&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile7.uf.tistory.com/original/16580B394FA0959422F5D5&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile7.uf.tistory.com/image/16580B394FA0959422F5D5&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;009.png&quot; height=&quot;194&quot; width=&quot;540&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;&lt;FONT color=#ff8b16&gt;admin site에 model 추가하기&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;아직 결정적인 부분을 소개하지 않았다. admin site에 우리가 만든 model을 추가할 수 있는데, 이러한 interface를 이용하여 손쉽게 object를 추가/변경/삭제할 수 있다. chater 5의 books 예제를를 적용해 보도록 하자.&lt;br /&gt;
&lt;br /&gt;books directory(mysite/books)에서 admin.py를 입력하고 다음 code를 기입한다.&lt;br /&gt;
&lt;/P&gt;&lt;PRE class=python name=&quot;code&quot;&gt;from django.contrib import admin
from mysite.books.models import Publisher, Author, Book

admin.site.register(Publisher)
admin.site.register(Author)
admin.site.register(Book)&lt;/PRE&gt;이 code에 의해 django admin site는 각각의 model을 제공받는다.&lt;br /&gt;
&lt;br /&gt;일단, 이를 수행하였다면, web browser를 통해 확인 바라며, &quot;Books&quot; section에 들어가 보기 바란다.&lt;br /&gt;
(잘하면, runserver를 다시 시작해야 할 지 모른다.)&lt;br /&gt;

&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile6.uf.tistory.com/original/127CF6404FA0B7E90A5B14&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile6.uf.tistory.com/image/127CF6404FA0B7E90A5B14&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;010.png&quot; height=&quot;270&quot; width=&quot;587&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile29.uf.tistory.com/original/1353EC434FA0B82D0B6F5E&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile29.uf.tistory.com/image/1353EC434FA0B82D0B6F5E&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;011.png&quot; height=&quot;217&quot; width=&quot;587&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile4.uf.tistory.com/original/201A8B3D4FA0B869289023&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile4.uf.tistory.com/image/201A8B3D4FA0B869289023&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;012.png&quot; height=&quot;172&quot; width=&quot;587&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile10.uf.tistory.com/original/196B01384FA0B95928E748&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile10.uf.tistory.com/image/196B01384FA0B95928E748&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;013.png&quot; height=&quot;417&quot; width=&quot;587&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile2.uf.tistory.com/original/1541B93B4FA0B99D31EF0C&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile2.uf.tistory.com/image/1541B93B4FA0B99D31EF0C&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;014.png&quot; height=&quot;417&quot; width=&quot;608&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile7.uf.tistory.com/original/136BD9394FA0BABA06578A&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile7.uf.tistory.com/image/136BD9394FA0BABA06578A&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;015.png&quot; height=&quot;656&quot; width=&quot;620&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;각각의 3개 model마다 admin inteface가 모두 지원되었다. 그것도 아주쉽게...&lt;br /&gt;
&lt;br /&gt;record 추가나 수정을 시도하여 database에 몇몇 data를 생산하기 바란다. 만약 이전의 chapter 5 예제를 실행하였다면, Publisher object에 이미 몇개의 data가 들어 있을 것이다.&lt;br /&gt;
&lt;br /&gt;가치있는 기능중 하나로, Book model에 대해 many-to-many relationship과 foreign key 처리이다. Book model은 다음과 같을 것이다.&lt;br /&gt;
&lt;PRE class=python name=&quot;code&quot;&gt;class Book(models.Model):
	title = models.CharField(max_length=100)
	authors = models.ManyToManyField(Author)
	publisher = models.ForeignKey(Publisher)
	publication_date = models.DateField()
	
	def __unicode__(self):
		return self.title&lt;/PRE&gt;&quot;Add book&quot; page에서, publisher(Foreign key)는 select box로 표현되고 authors field(ManyToManyField)는 다중 select box로 구성된다.&lt;br /&gt;

&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile8.uf.tistory.com/original/163C6A3A4FA0D2AF1A3886&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile8.uf.tistory.com/image/163C6A3A4FA0D2AF1A3886&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;016.png&quot; height=&quot;419&quot; width=&quot;587&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;두개의 field 모두 녹색의 + 버튼이 있는데, 이는 연관 records를 추가하도록 도와준다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;admin site 동작 방식&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;어떻게 admin site가 동작할까? 그다지 복잡하지는 않다.&lt;br /&gt;
&lt;br /&gt;server 시작시 urls.py로 부터 URLconf를 로드하였다면, admin을 활성화를 위한 기능으로 추가된 admin.autodiscover()를 실행한다. 이 함수는 INSTALLED_APP를 조사하고 각각의 installed app에 있는 admin.py를 호출한다. 주어진 app에 admin.py가 있다면, 해당 file에 있는 code를 실행한다.&lt;br /&gt;
&lt;br /&gt;books app에 있는 admin.py에서 각각 admin.site.register()를 단순히 호출하는데, admin으로 주어진 model이 등록(register)된 경우에만 그러하다. admin site는 명시적으로 등록된 model에 대해 edit/change interface를 표시만 하게 된다.&lt;br /&gt;
&lt;br /&gt;django.contrib.auth는 고유의 admin.py를 포함하는데, 이는 admin에 있는 Users와 Groups를 자동으로 표기하기 위함이다. 다른 django.contrib.redirects와 같은 django.contrib app은 역시 admin을 추가하는데, web으로 부터 download한 많은 3rd party django application을 수행한다.&lt;br /&gt;
&lt;br /&gt;그 밖에, django admin site는 단지 django application이고, 그것은 자체 model, template, view 그리고 URLpattern을 가직고 있다. 당신의 URLconf로 추가할 수 있고, 당신 고유의 view에 연결할 수 있다. template, view, 그리고 URLpattern을 검사할 수 있는데, 이는 django codebase의 당신 복사본에 django/contrib/admin을 찾는것에 의해서 가능하다. 그러나 admin site 동작 방식을 custom할 수 있는 많은 방법이 있더라도 직접 수정하는 유혹에 빠지지는 말자. (django admin application을 뒤지기로 결정했다면, model에 대해 metadata를 읽음으로 꽤나 정제된 행위를 할 수 있음을 명시하고, 그래서 code를 읽고 이해하는데 들어가는 비용을 줄일 수 있을 것이다.)&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;field optional 만들기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;잠시동안 admin site를 알아봤는데, 제약에 대해 주목해야 한다. edit forms은 모든 field가 채워져야 하는데, 대부분 optional field로 처리되길 바랄 것이다. 예를 들어, Author model의 email field를 optional하게 처리하는 것이다. 다시 말해, 비어있는 문자열을 허락하도록 하는 것이다. 현실 세계에서 모든 author가 email 주소를 가지는것이 아니기 때문이다.&lt;br /&gt;
&lt;br /&gt;email field가 optional임을 지정하기 위해 Book model(chapter 5에서 mysite/books/models.py에 있음)을 수정해야 한다. 다음과 같이 blank=True를 email field에 추가하면 된다.&lt;br /&gt;
&lt;/P&gt;&lt;PRE class=python name=&quot;code&quot;&gt;class Author(models.Model):
	first_name = models.CharField(max_length=30)
	last_name = models.CharField(max_length=40)
	email = models.EmailField(blank=True)&lt;/PRE&gt;이는 author의 email address가 빈값을 허락하라는 뜻이다. 기본값으로 blank=False인데, 빈값을 허락하지 않는다.&lt;br /&gt;
&lt;br /&gt;여기에서 재미있는 것이 있는데, __unicode()__ method를 제외하고 우리의 model은 database table의 정의대로 CREATE TABLE sql statement의 표현 형태로&amp;nbsp;서비스되었다. blank=True를 추가하여 database table의 형상을 간단히 정의한 것을 넘어 우리의 model을 확장하기 시작한 것이다. 이제 우리의 model class는 Author object가 무었인지 그리고 무었을 할 수 있는지에 대한 지식의 집합을 좀더 풍부하게 다루기 시작한 것이다. VARCHAR column으로 database에 email field를 표현되도록 한것 뿐만 아니라, django admin site에 optional field로 선언하였다.&lt;br /&gt;
&lt;br /&gt;blank=True로 선언하였다면, &quot;Add author&quot;(&lt;A href=&quot;http://127.0.0.1:8000/admin/books/author/add/&quot;&gt;http://127.0.0.1:8000/admin/books/author/add/&lt;/A&gt;)를 다시 읽고 &quot;Email&quot; 글자가 bold체가 아님을 확인할 수 있다. 이는 요구하는 값이 아님을 나타나는 뜻으로 email 주소 없이 추가할 수 있다.&lt;br /&gt;

&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile10.uf.tistory.com/original/110E51504FA0E6DB0FB62D&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile10.uf.tistory.com/image/110E51504FA0E6DB0FB62D&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;017.png&quot; height=&quot;303&quot; width=&quot;587&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;&lt;br /&gt;
&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;&lt;FONT color=#7293fa&gt;date와 numeric field optional 만들기&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;blank=True와 연관되어 date와 numeric field에도 적용되리라 생각할 수 있는데, 이는 배경 설명이 추가로 필요하다.&lt;br /&gt;
&lt;br /&gt;SQL은 빈값을 지정하는 고유의 방법으로, NULL을 사용한다. NULL은 &quot;모름(unknown)&quot;을 의미하거나 &quot;무효한(invalid)&quot; 혹은 기타 다른 정의로 사용되기도 한다.&lt;br /&gt;
&lt;br /&gt;SQL에서 NULL 값은 비어있는 문자열과 다른 의미인데, 이는 python object인 None이 비어있는 문자 &quot;&quot;와 다른것과 마찬가지 이다. 이는 특정 문자 field(예, VARCHAR)가 NULL 값과 비어있는 문자열 두개 모두 가능하다는 것이다.&lt;br /&gt;
&lt;br /&gt;이는 애매함과 혼란을 야기한다 : &quot;왜 이 record는 NULL을 가지고 있고, 다른것은 비어있는 문자열이지? 그들간의 차이점이나 data 불일치(inconsistency)가 발생하지 않을까?&quot;이다. 그리고 : &quot;어떻게 비어있는 값을 가진 모든 record를 구할 것인지? 혹은 NULL record나 비어있는 문자열에 대해서도 혹은 비어있는 문자로 하나를 고르기만 한다면?&quot;&lt;br /&gt;
&lt;br /&gt;이러한 애매함을 없애기 위해, django의 자동 생성된 CREATE TABLE statement(chapter 5에서 언급)는 NOT NULL을 각 column 정의부에 명시적으로 추가할 수 있다. 예를 들어, chapter 5로 부터의 Author model에을 위해 생성된 statement이다.&lt;br /&gt;
&lt;PRE class=sql name=&quot;code&quot;&gt;CREATE TABLE &quot;books_author&quot; (
    &quot;id&quot; serial NOT NULL PRIMARY KEY,
    &quot;first_name&quot; varchar(30) NOT NULL,
    &quot;last_name&quot; varchar(40) NOT NULL,
    &quot;email&quot; varchar(75) NOT NULL
)
;&lt;/PRE&gt;대부분 이것의 기본 동작은 optional이며 data 불일치는 발생하지 않을 것이다. 그리고 admin site와 같은 django의 나머지 부분에도 잘 동작하는데, 만약 field를 비운채 저장하게 된다면, NULL 값이 아닌 빈 문자를 추가하게 된다.&lt;br /&gt;
&lt;br /&gt;그러나 date, time, 그리고 number와 같은 비어있는 문자열을 유효한 값으로 받아들일 수 없는 databas column type이 있다. 만약 date나 integer column에 비어있는 문자열로 추가하려고 한다면, 사용하는 database 종류에 따라(PostgreSQL은 엄격하게 예외를 발생함. MySQL은 받아줄 수도 없을 수도 있음), database 오류를 받게 된다. 이런 경우 NULL이 비어있는 값을 정의하는데 유일하게 사용된다. django model에서 null=True를 field에 추가하여 NULL을 허용할 수 있도록 한다.&lt;br /&gt;
&lt;br /&gt;다음을 언급하기 위해 많이 돌아왔다 : 만약 data field(예, DateField, TimeField, DateTimeField) 혹은 numeric field(예, IntegerField, DecimalField, FloatField)에 blank 값을 허용하려한다면, null=True&lt;EM&gt;와&lt;/EM&gt; blank=True를 모두 사용해야 한다.&lt;br /&gt;
&lt;br /&gt;예들 들어, Book model을 변경하여 publication_date에 blank를 가능하게 만들어보자.&lt;br /&gt;
&lt;PRE class=python name=&quot;code&quot;&gt;class Book(models.Model):
	title = models.CharField(max_length=100)
	authors = models.ManyToManyField(Author)
	publisher = models.ForeignKey(Publisher)
	publication_date = models.DateField(blank=True, null=True)&lt;/PRE&gt;null=True를 추가는것은 blank=True를 추가하는 것보다 더 복잡한데, null=True는 database의 의미(semantic)를 변경시키기 때문이고 그러므로, publication_date field로 부터 NOT NULL을 지우기 위해 CREATE TABLE statement를 변경한다.&lt;br /&gt;
&lt;br /&gt;이러한 몇몇 이유로 django는 database schema를 자동으로 변경하지 않는다. 그래서 model을 변경할 때 마다 적합한 ALTER TABLE statement를 실행해야 하는 책임이 있다. &lt;FONT color=#ff8b16&gt;manage.py &lt;STRONG&gt;dbshell&lt;/STRONG&gt;&lt;/FONT&gt;를 실행하여 database server의 shell에 들어가자. 다음이 NOT NULL을 제거하는 방법이다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;C:\mydjango\mysite&amp;gt;&lt;FONT color=#ff8b16&gt;python manage.py &lt;STRONG&gt;dbshell&lt;/STRONG&gt;&lt;br /&gt;
&lt;/FONT&gt;SQLite version 3.7.11 2012-03-20 11:35:50&lt;br /&gt;
Enter &quot;.help&quot; for instructions&lt;br /&gt;
Enter SQL statements terminated with a &quot;;&quot;&lt;br /&gt;
sqlite&amp;gt; &lt;FONT color=#ff8b16&gt;ALTER TABLE books_book ALTER COLUMN publication_date DROP NOT NULL;&lt;br /&gt;
&lt;/FONT&gt;Error: near &quot;ALTER&quot;: syntax error&lt;br /&gt;
sqlite&amp;gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;(본 SQL 문법은 PostgreSQL에 해당되며, sqlite에서는 위와 같이 오류가 발생함)&lt;br /&gt;

&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile4.uf.tistory.com/original/180FCA424FA217B52AFA2E&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile4.uf.tistory.com/image/180FCA424FA217B52AFA2E&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;018.png&quot; height=&quot;415&quot; width=&quot;580&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;이러한 shema 변경은 chapter 10에서 보다 자세히 다룰 것이다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;field label 수정(customizing) 하기&lt;/SPAN&gt;&lt;br /&gt;
&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
admin site의 edit form에서 각 field label은 field 이름으로 부터 생성된다. 그 알고리즘은 간단한데, django는 '_'를 ' '로, 앞 문자를 대문자로 변경한다. 예를 들어, publication_date는 &quot;Publication date&quot;로 변경된다.&lt;br /&gt;
&lt;br /&gt;그러나, field name은 field label로 사용하기 어려울 때도 있는데, 이런 경우에 label을 수정할 수 있다. verbose_name을 model field에 지정하여 가능해 진다.&lt;br /&gt;
&lt;br /&gt;예를 들어, Author.email field를 &quot;e-mail&quot;로 변경하고자 한다면 다음을 참고한다.&lt;br /&gt;
&lt;br /&gt;&lt;PRE class=python name=&quot;code&quot;&gt;class Author(models.Model):
	first_name = models.CharField(max_length=30)
	last_name = models.CharField(max_length=40)
	email = models.EmailField(blank=True, verbose_name='e-mail')&lt;/PRE&gt;변경하고 server를 다시 시작하면, edit form에 label이 변경된것을 확인할 수 있다.&lt;br /&gt;

&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile10.uf.tistory.com/original/204D783D4FA2226C149304&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile10.uf.tistory.com/image/204D783D4FA2226C149304&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;019.png&quot; height=&quot;301&quot; width=&quot;580&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
verbose_name을 사용하면 첫 글자는 &lt;EM&gt;항상&lt;/EM&gt; 대문자로 표시된다. &lt;br /&gt;
&lt;br /&gt;마지막으로 verbose_name을 위치가 있는 argument로 전달할 수 있는데, 이는 보다 간편한 문법이다. 아래는 그 예이다.&lt;br /&gt;
&lt;/P&gt;&lt;PRE class=python name=&quot;code&quot;&gt;class Author(models.Model):
	first_name = models.CharField(max_length=30)
	last_name = models.CharField(max_length=40)
	email = models.EmailField('e-mail', blank=True)&lt;/PRE&gt;이는 ManyToManyField나 ForeignKey field는 동작하지 않는데, 이는 첫 argument에 model class가 들어가기 때문이다. 이런 경우에는 verbose_name을 명시적으로 지정해야 한다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;ModelAdmin class 수정하기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;여태껏 우리가 알아본 blank=True, null=True 그리고 verbose_name은 model-level 수정으로, 정확히 얘기하자면 admin-level 수정은 아니다. 이는 이러한 수정 사항들은 model의 한 부분이며 admin site에 의해 사용될 뿐이다. admin-specific은 아니다.&lt;br /&gt;
&lt;br /&gt;django admin은 admin site가 특정 model에 어떻게 동작하는지를 수정(customize)할 수 있는 option을 제공한다. 이러한 option은 ModelAdmin class에 있으며, 이는 특정 admin site instance에 있는 특정 model을 위한 설정을 포함하고 있는 class이다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#7293fa&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;수정 목록(change&amp;nbsp;list) 변경(custom)하기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;Author model에 표시되는&amp;nbsp;수정 목록을 변경해 보도록 하자. 기본적으로&amp;nbsp;수정 목록은 각 object에 대해 __unicode__()의 결과를 표시한다. chapter 5에서 __unicode()__ method를 정의하였다.&lt;br /&gt;
&lt;br /&gt;&lt;PRE class=python name=&quot;code&quot;&gt;class Author(models.Model):
	first_name = models.CharField(max_length=30)
	last_name = models.CharField(max_length=40)
	email = models.EmailField('e-mail', blank=True)
	
	def __unicode__(self):
		return u'%s %s' % (self.first_name, self.last_name)&lt;/PRE&gt;결과적으로 Author object의&amp;nbsp;수정 목록은 각각의 성과 이름을 함께 표시한다.&lt;br /&gt;

&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile5.uf.tistory.com/original/117FF2444FA3267820E545&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile5.uf.tistory.com/image/117FF2444FA3267820E545&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;020.png&quot; height=&quot;354&quot; width=&quot;580&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;변경 내역에 다른 field를 추가하여 기본 동작을 향상시킬 수 있다. 예를 들어, author의 e-mail 주소를 표기하고, 성과 이름을 정렬가능토록 한다.&lt;br /&gt;
&lt;br /&gt;이를 해결하기 위해 Author model에 ModelAdmin class를 정의한다. 이 class는 admin을 수정하는 키가 되는데 변경 내역 page를 표시하기 위한 field의 목록을 지정하도록 해주는 가장 기본적인 것중 하나이다. 다음과 같이 admin.py를 수정하면 된다.&lt;br /&gt;
&lt;br /&gt;&lt;/P&gt;&lt;PRE class=python name=&quot;code&quot;&gt;from django.contrib import admin
from mysite.books.models import Publisher, Author, Book

class AuthorAdmin(admin.ModelAdmin):
    list_display = ('first_name', 'last_name', 'email')

admin.site.register(Publisher)
admin.site.register(Author, AuthorAdmin)
admin.site.register(Book)&lt;/PRE&gt;여기에서 우리가 한것을 정리하면 다음과 같다.&lt;br /&gt;

&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;AuthorAdmin class를 정의하였다. 이 class는 django.contrib.admin.ModelAdmin을 상속받았고, admin model에 변경할 설정을 가지고 있다. &quot;list_display&quot;라는 단 하나의 수정을 지정하였는데 수정 목록에 표시할 field 이름을 정리한 것이다. 이 field 이름들은 model에 반드시 존재해야 한다.&lt;/LI&gt;
&lt;LI&gt;admin.site.register() 호출을 Autor 다음에 AuthorAdmin을 추가하여 변경하였는데, 이는 다음과 같이 해석할 수 있다. : &quot;AuthorAdmin option으로 Author model을 등록하라.&quot;&lt;br /&gt;
&lt;br /&gt;admin.site.register() 함수는 ModelAdmin subclass를 두번째 argument로 option 처리하여 받아들인다. 만약 두번째 argument를 정의하지 않았다면, django는 해당 model에 대해 기본 admin option을 사용할 것이다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;이러한 변경된 사항을 가지고 해당 page를 다시 불러보자. 그리고 3개의 column으로 표시됨 확인할 수 있다. 덧붙여 column header를 클릭하면 정렬이 실행된다.&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile2.uf.tistory.com/original/1248BC3F4FA326EF1E66D6&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile2.uf.tistory.com/image/1248BC3F4FA326EF1E66D6&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;021.png&quot; height=&quot;356&quot; width=&quot;580&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
다음으로 간단한 검색 바(search bar)를 추가해 보자. search_fields를 AuthorAdmin에 추가한다.&lt;br /&gt;
&lt;/P&gt;&lt;PRE class=python name=&quot;code&quot;&gt;class AuthorAdmin(admin.ModelAdmin):
	list_display = ('first_name', 'last_name', 'email')
	search_fields = ('first_name', 'last_name')&lt;/PRE&gt;해당 page를 다시 읽으면 화면 상단에 검색 바가 뜨게 된다. 우리는 단지 admin 수정 목록에 first_name과 last_name field로 검색할 수 있는 검색 바를 포함하도록 알려줬을 뿐이다. 기대한 것처럼 대소문자 구별이 없으며, &quot;bar&quot;라고 검색하면 Barney 성과 Hobarson 이름을 찾게 된다.&lt;br /&gt;

&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile2.uf.tistory.com/original/1579BE354FA32CA23461EE&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile2.uf.tistory.com/image/1579BE354FA32CA23461EE&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;022.png&quot; height=&quot;357&quot; width=&quot;580&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
다음으로, 수정 모록에 date filter를 추가해 보도록 하자.&lt;br /&gt;
&lt;/P&gt;&lt;PRE class=python name=&quot;code&quot;&gt;from django.contrib import admin
from mysite.books.models import Publisher, Author, Book

class AuthorAdmin(admin.ModelAdmin):
	list_display = ('first_name', 'last_name', 'email')
	search_fields = ('first_name', 'last_name')

class BookAdmin(admin.ModelAdmin):
	list_display = ('title', 'publisher', 'publication_date')
	list_filter = ('publication_date',)

admin.site.register(Publisher)
admin.site.register(Author, AuthorAdmin)
admin.site.register(Book, BookAdmin)&lt;/PRE&gt;다른 종류의 option을 다루기때문에, BookAdmin이라는 구별된 ModelAdmin class를 생성하였다. 처음으로 list_display를 수정하였으며, 그다음 lists_filter를 사용하였는데, 이는 수정 목록 page의 오른족에 사용할 filter를 생성할수 있는 tuple을 지정하도록 한다. date field는 &quot;오늘&quot;, &quot;과거 7일&quot;, &quot;이번달&quot;, 그리고 &quot;올해&quot;에 대한 filter를 제공한다. 다음과 같이 표시된다.&lt;br /&gt;

&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile29.uf.tistory.com/original/140CB93F4FA331E8147C0E&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile29.uf.tistory.com/image/140CB93F4FA331E8147C0E&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;023.png&quot; height=&quot;258&quot; width=&quot;580&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
list_filter는 역시 DateField 이외의 다른 type의 field에서도 작동한다. 최소 2개 이상이 선택되었을때 표시된다,&lt;br /&gt;
&lt;br /&gt;date filter를 제공하는 다른 방법으로 date-hierarchy admin option을 사용하는 것이다.&lt;br /&gt;
&lt;/P&gt;&lt;PRE class=python name=&quot;code&quot;&gt;class BookAdmin(admin.ModelAdmin):
	list_display = ('title', 'publisher', 'publication_date')
	list_filter = ('publication_date',)
	date_hierarchy = 'publication_date'&lt;/PRE&gt;이것으로 수정 목록 page는 목록 상단에 navigation bar가 나타난다. 가능한 년도와 함께 시작되며, 달과 개별 일에 대해 더 상세히 들어갈 수 있다.&lt;br /&gt;

&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile23.uf.tistory.com/original/1845DB504FA3353A2179B6&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile23.uf.tistory.com/image/1845DB504FA3353A2179B6&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;024.png&quot; height=&quot;283&quot; width=&quot;580&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
date_hierarchy는 tuple이 아닌 문자열을 받아들인다. 이는 하나의 date field만 받아들이기 위해서이다.&lt;br /&gt;
&lt;br /&gt;마지막으로 기본 정렬을 변경하는 것으로, 수정 목록 page가 표시될 때 항상 publication date에 의해 내림차순으로 정렬되도록 하는 것이다. 기본으로는 수정 목록은 class Meta(chapter 5) 범위 내의 model의 정렬을 따르게 되는데, ordering 값을 지정하지 않았다면, 정렬의 순서는 정의되지 않은 것이다.&lt;br /&gt;
&lt;br /&gt;&lt;/P&gt;&lt;PRE class=python name=&quot;code&quot;&gt;class BookAdmin(admin.ModelAdmin):
	list_display = ('title', 'publisher', 'publication_date')
	list_filter = ('publication_date',)
	date_hierarchy = 'publication_date'
	ordering = ('-publication_date',)&lt;/PRE&gt;이 admin ordering option은 model들의 class Meta에 ordering을 따르도록 되어 있는데, list에 있는 첫 field name을 사용하도록 되어 있다. field 이름의 tuple 혹은 list를 전달하고, 내림차순 정렬인 경우 앞에 '-'를 붙여 주면 된다.&lt;br /&gt;
&lt;br /&gt;해당 page를 다시 읽으면 다음과 같다. &quot;Publication date&quot; header는 이제 작은 화살표 표시가 포함되고 관련 record들은 그에 따라 정렬되어 있다.&lt;br /&gt;

&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile27.uf.tistory.com/original/144AB6504FA33BAF2A21EC&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile27.uf.tistory.com/image/144AB6504FA33BAF2A21EC&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;025.png&quot; height=&quot;286&quot; width=&quot;580&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
수정 목록을 변경하는 주요한 내용을 다뤘다. 이러한 option을 사용하면서 강력하고 생산적인 data 편집 interface를 단 몇줄로 만들 수 있다.&lt;br /&gt;
&lt;br /&gt;&lt;FONT color=#7293fa&gt;&lt;FONT style=&quot;BACKGROUND-COLOR: #ffffff&quot;&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;edit form 수정하기(customizing)&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;br /&gt;
&lt;/FONT&gt;&lt;br /&gt;
수정 목록을 수정한것 처럼 edit form도 많은 방법으로 변경이 가능하다.&lt;br /&gt;
&lt;br /&gt;처음으로 field의 순서를 수정해 보자. 기본으로 field의 순서는 model에서 정의한 순서를 따르도록 되어 있다. ModelAdmin 상속 class의 fields option을 이용하여 순서를 변경할 수 있다.&lt;br /&gt;
&lt;/P&gt;&lt;PRE class=python name=&quot;code&quot;&gt;class BookAdmin(admin.ModelAdmin):
	list_display = ('title', 'publisher', 'publication_date')
	list_filter = ('publication_date',)
	date_hierarchy = 'publication_date'
	ordering = ('-publication_date',)
	fields = ('title', 'authors', 'publication_date', 'publisher')
&lt;/PRE&gt;이렇게 되면 edit form에서 field의 순서가 변경되게 된다.&lt;br /&gt;

&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile1.uf.tistory.com/original/174BAC424FA35D9B15D455&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile1.uf.tistory.com/image/174BAC424FA35D9B15D455&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;026.png&quot; height=&quot;447&quot; width=&quot;580&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
다른 유용한 fields 옵션으로 전체가 편집되는 것으로 부터 특정 field를 &lt;EM&gt;제외&lt;/EM&gt;할 수 있도록 한다. 단지 제외할 field(들)을 비워두면 된다. 만약 당신의 admin user들이 당신 data의 특정 부분을 편집하는데 신뢰된다던지 외부에 의해 field의 일부가 변경되는 경우 사용하면 된다. 예를 들어, book database에서 publication_date field를 편집하지 못하도록 할 수 있다.&lt;br /&gt;
&lt;/P&gt;&lt;PRE class=python name=&quot;code&quot;&gt;class BookAdmin(admin.ModelAdmin):
	list_display = ('title', 'publisher', 'publication_date')
	list_filter = ('publication_date',)
	date_hierarchy = 'publication_date'
	ordering = ('-publication_date',)
	fields = ('title', 'authors', 'publisher')&lt;/PRE&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile25.uf.tistory.com/original/13579E4E4FA3603E1D80B6&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile25.uf.tistory.com/image/13579E4E4FA3603E1D80B6&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;027.png&quot; height=&quot;392&quot; width=&quot;580&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
결과적으로 books를 위한 edit form은 publication date를 지정할 방법을 제공하지 않는다. 이는 분명 유용한데, 다시 말해, 만약 publication date를 미루지 않는&amp;nbsp;author를 선호하는 편집자라면 그렇다.&lt;br /&gt;
&lt;br /&gt;user가 새로운 book을 추가할 때 이러한 불완전한 form을 사용한다면, django는 간단히 publication_date를 None으로 간주한다. 이는 즉 해당 field는 null=True가 되어 있어야 한다.&lt;br /&gt;
&lt;br /&gt;다른 것으로 many-to-many field에 대한 수정이 있다. book에 대한 edit form을 보았는데, admin site는 각각 ManyToManyField를 multiple-select box로 표현하는데, 이는 대부분의 논리적인 HTML 입력 widget이다. 그러나 multiple-select box는 사용하기가 불편하다. 만약 여러개의 item을 선택하려 한다면, CTRL 키를 누른채 선택해야 한다. admin site는 이것을 쉽게 설명하는 text를 추가할 수 있도록 해준다. 그러나 여전이 수백개를 포함하는 경우에는 다루기가 불편하다.&lt;br /&gt;
&lt;br /&gt;admin site의 결론은 filter_horizontal이다. BookAdmin을 추가하고 확인해보자.&lt;br /&gt;
&lt;/P&gt;&lt;PRE class=python name=&quot;code&quot;&gt;class BookAdmin(admin.ModelAdmin):
	list_display = ('title', 'publisher', 'publication_date')
	list_filter = ('publication_date',)
	date_hierarchy = 'publication_date'
	ordering = ('-publication_date',)
	filter_horizontal = ('authors',)&lt;/PRE&gt;(만약 여기까지 따라왔다면, 앞선 fields option을 제거했다)&lt;br /&gt;
&lt;br /&gt;다시 page를 읽어 들이면, &quot;Authors&quot; section을 보게 되고, 그것은 동적으로 option을 통해 검색을 가능케하고 &quot;Available authors&quot;로 부터 &quot;Chosen authors&quot; box로 혹은 그 역으로 특정 author를 이동할 수 있도록 하는 장식된 JavaScript filter를 사용한다.&lt;br /&gt;
&lt;br /&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile7.uf.tistory.com/original/197D5D3F4FA365DC0A65A9&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile7.uf.tistory.com/image/197D5D3F4FA365DC0A65A9&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;028.png&quot; height=&quot;668&quot; width=&quot;605&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
10개 이상의 item을 가지는 ManyToManyField는 filter_horizental를 사용할 것을 권장한다. 이전의 간단한 multiple-select widget 보다 사용하기 편리하기 때문이다. 또한 filter_horizontal을 다중 filed에도 사용할 수 있다. 단지 tuple에 각 이름을 지정하면 된다.&lt;br /&gt;
&lt;br /&gt;ModelAdmin class는 역시 filter_vertical option도 지원한다. 이는 filter_horizontal과 동일하게 작동하나, JavaScript interface 결과를 수직대신 수평으로 쌓게 한다. 이는 단지 개인의 취향이다.&lt;br /&gt;
&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile27.uf.tistory.com/original/201834394FA367681C46BE&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile27.uf.tistory.com/image/201834394FA367681C46BE&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;029.png&quot; height=&quot;738&quot; width=&quot;605&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
filter_horizontal과 filter_vertical은 ManyToManyField fields에만 동작하고, ForeignKey field는 동작하지 않는다. 기본으로 admin site는 간단한 &amp;lt;select&amp;gt; box를 ForeignKey field를 사용하나 ManyToManyField는 가끔 drop-down으로 표시되는 관계있는 object를 선택하는데 여러 부하가 발생하는 것이 발생되지 않길 원할 것이다. 예를 들어, 만약 book database에서 publisher가 수천개가 이를 정도로 커진다면, &quot;Add book&quot; form은 load하는데도 오래 걸릴 것이다. 왜냐하면 모든 publisher를 load해야 &amp;lt;select&amp;gt; box에 표시할 수 있기 때문이다.&lt;br /&gt;
&lt;br /&gt;이를 해결하기 위해 raw_id_fields를 사용하면 된다. ForeignKey field 이름으로 tuple 값을 세팅하고 이 fields는 간단한 text input box로 표시될 것이다.&lt;br /&gt;
&lt;br /&gt;&lt;/P&gt;&lt;PRE class=python name=&quot;code&quot;&gt;class BookAdmin(admin.ModelAdmin):
	list_display = ('title', 'publisher', 'publication_date')
	list_filter = ('publication_date',)
	date_hierarchy = 'publication_date'
	ordering = ('-publication_date',)
	filter_horizontal = ('authors',)
	raw_id_fields = ('publisher',)&lt;/PRE&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile29.uf.tistory.com/original/172C0A4D4FA36EA4118639&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile29.uf.tistory.com/image/172C0A4D4FA36EA4118639&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;030.png&quot; height=&quot;672&quot; width=&quot;605&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
input box에는 그럼 무었을 입력하는가? publisher에 해당되는 database id가 그 답이다. 보통 사람은 database id를 기억하지 못하므로, 옆의 돋보기 버튼을 통해서 선택할 수 있다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;Users, Groups, 그리고 Permissions&lt;/SPAN&gt;&lt;br /&gt;
&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
supseruser로 로그하였기 때문에, 당신은 임의의 object에 대해 생성, 편집, 그리고 삭제할 수 있다. 다른 환경은 다른 permission 시스템을 요구하기도 하는데, 모든이가 할 수 없도록 한다던지, superuser 이여야 한다던지가 해당된다. django의 admin site는 permission 시스템을 사용하는데, 그것은 그들이 필요한 interface의 단지 일부분만 특정 사용자가 접근 가능하게 해준다.&lt;br /&gt;
&lt;br /&gt;이러한 user 계정은 admin interface의 외부에서도 일반적으로 필요하다는 의미인데, 여기서는 admin user 계정에 한해서만 다루도록 한다. chapter 14에서 당신 site의 그 나머지에서 user 계정을 통합하는 것을 다루도록 한다. (admin site 뿐만 아니라)&lt;br /&gt;
&lt;br /&gt;당신은 다른 object와 유사한 admin interrface를 통해 user와 permission을 편집할 수&amp;nbsp;있다. 우리는 본 chapter 일찍이 Admin의 User와 Group section을 둘러보았다. User object는 표준 username, password, e-mail, 그리고 실명 field를 가지고 있으며 덧붙여 그 user에게 어떤 admin interface를 허락할지를 정의한 field도 있다. 우선, 다음과 같이 3개의 boolean flag를 가지고 있다.&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;&quot;active&quot; flag는 user의 활성화 여부를 조절한다. 만약 이 flag가 off라면 해당 user는 password가 맞더라도 log-in 할 수 없다.&lt;/LI&gt;
&lt;LI&gt;&quot;staff&quot; flag는 admin interface레 log-in을 허락할지를 조절한다. public user와 administrator를 구별하는데 사용되는데, 자세한건 chapter 14에서 다룬다.&lt;/LI&gt;
&lt;LI&gt;&quot;superuser&quot; flag는 추가할 admin interface에서 item을 생성하고 삭제하는 모든 access를 준다. 만약 해당 flag가 on이라면 모든 일반적인 permission은 무시된다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&quot;일반&quot;적인 admin user, 다시 말해 active, non-superuser staff는 할당된 permission을 통해 admin 접근이 허가된다. admin interface를 통해 편집가능한 각 object는 3개의 permission을 가진다 : create permission, edit permission, 그리고 delete permission. permission을 user에게 할당하는 것은 이러한 permission에 의해 설명된 것들에 대한 접근을 허가한다.&lt;br /&gt;
&lt;br /&gt;만약 user를 생성할 때, 그 user에게 permission이 없고 이는 user 지정 permission을 부여하는 것에 달려있다. 예를 들어 publisher를 추가하고 변경하는 permission을 임의의 user에게 부여했으나 삭제할 permission을 주지 않았다면, 이러한 permission은 model 당 정의되어 있고, object 당 정의된 것이 아니다. &quot;John은 어떤 책이라도 변경할 수 있다&quot;이지 &quot;John은 Apress에 의해 publish된 어떤 책을 변경할 수 있다&quot;는 아니다. 뒷 부분 즉 object당 permission은 조금 복잡하고 이 책의 범위를 벗어난다. 그러나 django document에서 다루고 있다.&lt;br /&gt;
&lt;br /&gt;역시 user를 group에 할당할 수 있다. &lt;EM&gt;group&lt;/EM&gt;은 해당 group의 모든 멤버에게 적용할 permission의 집합이라고 생각하면 된다. group은 user 일부에게 동일한 permission을 부여하는데 유용하다.&lt;br /&gt;
&lt;br /&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;&lt;STRONG&gt;언제 그리고 왜 admin interface를 이용해야 하는가? 그리고 언제 사용하면 안되는가?&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;br /&gt;
&lt;br /&gt;본 chapter를 통해 django의 admin site를 사용하는 좋은 아이디어가 있을지 모른다. 그러나 &lt;EM&gt;언제 &lt;/EM&gt;그리고 &lt;EM&gt;왜 &lt;/EM&gt;사용하는지를 다루고, 그리고 언제 사용하면 &lt;EM&gt;안되는지&lt;/EM&gt;도 확인해 보자.&lt;br /&gt;
&lt;br /&gt;django의 admin site는 특별히 빛나는데, 이는 비-기술자 user가 data에 접근할 때 이다. django가 처음 개발되었을 때 일상적인 온라인 기능의 개발은 다음과 같이 어디론가 가버렸다라고&amp;nbsp;신문에서&amp;nbsp;언급다.&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;project에 책임있는 reporter는 개발자중 한명을 만나고 가능한 data를 설명한다.&lt;/LI&gt;
&lt;LI&gt;개발자는 해당 data에 적합한 django model을 설계하고 reporter에게 admin site를 개설한다.&lt;/LI&gt;
&lt;LI&gt;reporter는 누락되거나 관계없는 field를 찾기 위해 admin site를 검사하여 좀더 좋게 만든다. 개발자는 model을 반복하여 변경한다.&lt;/LI&gt;
&lt;LI&gt;model에 동의되었다면, reporter는 admin site를 사용하여 data에 들어가보기 시작한다. 그와 동시에 프로그래머는 공개적으로 접근가능한 view와 template를 개발하는데 촛점을 맞출수 있다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;다른말로, django admin interface의 존재 이유는 컨텐츠 생산자와 프로그래머의 작업을 연속적으로 작업을 가능하게 한다.&lt;br /&gt;
&lt;br /&gt;그러나 admin site는 다른 몇가지 경우에 의해서도 유용하다.&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;&lt;EM&gt;data model 검사(inspect)&lt;/EM&gt; : 몇몇 model을 정의하였다면, admin interface에서 호출하고 몇몇 dummy daat를 입력하는것등이 꽤나 유용할 때가 있다. 몇가지 경우에서 이는 data-modeling 실수 혹은 model에서 발생하는 다른 문제를 드러내 주기도 한다.&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;습득(aquire)된 data 관리&lt;/EM&gt; : 외부 source(사용자 혹은 web crawler)로 부터 들어오는 data에 의존하는 application을 위해 admin site는 data의 검사 혹은 편집을&amp;nbsp;쉽게 하는&amp;nbsp;방법을 제공한다. database의 command-line utility 보다는 powerful 하지 않지만 훨씬 더 편리하다는 생각이 들 것이다.&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;빠르고 더러운(quick and dirty) data 관리 app&lt;/EM&gt; : admin site를 data 관리 app으로 스스로 만들어 사용할 수 있다. 다시 말해 비용을 추적한다는 뜻이다. 만약 공개하지 않고 당신 고유의 필요에의해 무엇인가 만든다면 admin site는 먼길을 제시한다. 이런 의미에서 당신은 그것을 보강된 것으로 생각할 수 있고 spreadsheet의 유사한 버전으로 간주된다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;명확한 한가지는 다음과 같다. : admin site는 가장 중요한 것은 아니다. 몇년 동안 의도적으로 서비스하지 않는 기능을 제공하기 위해 수정하고 자르는것을 봐왔다. 그것은 data에 대한 &lt;EM&gt;공개적인 &lt;/EM&gt;interface로 의도되지 않았거나 data의 정제된 정렬과 검색을 허락하는 의도로 만들어졌다. 본 chapter 앞부분에서 알린바와 같이, 신뢰된 site 관리자를 위한 것이다. 이것을 잘 염두해둬야 admin site 사용을 효과적으로 사용할 수 있는 key가 된다.&lt;/P&gt;&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-126-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-126-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=28864001&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/126&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/django&quot;&gt;django&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/django/the%20django%20book%20study&quot;&gt;the django book study&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/126&quot; &gt;[06] django admin site&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(2)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/27&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/125&quot; &gt;[05] django의 model&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(1)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/124&quot; &gt;[04] django의 template&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(2)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/123&quot; &gt;[03] django 1.4의 view와 urlconfs&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/04&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/122&quot; &gt;[02] django 1.4 설치와 project 생성하기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/120&quot; &gt;[01] django 소개&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/28&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>the django book study</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/126</guid>
			<comments>http://greenfishblog.tistory.com/126#entry126comment</comments>
			<pubDate>Fri, 27 Apr 2012 14:13:41 +0900</pubDate>
		</item>
		<item>
			<title>[05] django의 model</title>
			<link>http://greenfishblog.tistory.com/125</link>
			<description>참조 : &lt;A href=&quot;http://www.djangobook.com/en/2.0/chapter05/&quot; target=&quot;&quot;&gt;http://www.djangobook.com/en/2.0/chapter05/&lt;/A&gt;&lt;br /&gt;
&lt;br /&gt;chapter 3에서 django의 view와&amp;nbsp;URLconf를 이용하여 동적 web site를 구축하는 기초적인 방법을 알아보았다. view는 몇몇 임의의 logic을 책임진다고 설명하였고, response를 전달하게 된다. 그 예중 하나는 현재의 시각을 계산하는 logic이었다.&lt;br /&gt;
&lt;br /&gt;최근의 web application에서 임의의 logic은 종종 database와 연동된다. 알게 모르게 &lt;EM&gt;database 중심의 web site(database-driven web site)&lt;/EM&gt;는 database server에 접속하고 data를 전달 받은뒤 web page에 표시한다. 그 site는 방문자를 위해 그들 고유의 database를 창출하도록 기능을 제공하기도 한다.&lt;br /&gt;
&lt;br /&gt;많은 복잡한 web site는 그 두개를 조합하기도 한다. 예를 들어, amazon.com은 database 기반 site의 휼륭한 본보기가 된다. 각 제품 page는 amazon 제품의 database의 query 결과를 가지고 HTML 형태로 format되고, 고객 review를 전송할때 review의 database로 insert한다.&lt;br /&gt;
&lt;br /&gt;django는 database 중심의 web site를 만들기에 적합하게 설계되었다. 왜냐하면 python을 이용하면 database query 수행을 위한 강략한 도구가 함께 따르기 때문이다. 본 chapter에서는 django의 database 계층읠 기능에 대해 설명한다.&lt;br /&gt;
&lt;br /&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;view에서&amp;nbsp;database query를 수행하는 &quot;멍청한&quot; 방법&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;br /&gt;
&lt;br /&gt;chapter 3에서 view에서 hard-code된 text를 직접 사용했던 &quot;멍청한&quot; 방법처럼, view에서 database로 부터 직접 data를 전달받는 &quot;멍청한&quot; 방법도 있다. 그것은 간단한데, sql query를 수행하기 위한 python library를 호출하고 그 결과를 이용하는 것이다.&lt;br /&gt;
&lt;br /&gt;이러한 예제 view에서는, MySQLdb library를 이용할 것인데, MySQL database에 접속하고 record를 구해 template에 전달하여 web page로 출력하게 된다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 361px; HEIGHT: 263px&quot; class=python rows=11 cols=37 name=code&gt;from django.shortcuts import render_to_response
import MySQLdb

def book_list(request):
	db = MySQLdb.connect(user='me', db='mydb', passwd='secret', host='localhost')
	cursor = db.cursor()
	cursor.execute('SELECT name FROM books ORDER BY name')
	names = [row[0] for row in cursor.fetchall()]
	db.close()
	return render_to_response('book_list.html', {'names': names})&lt;/TEXTAREA&gt;&lt;br /&gt;
이러한 접근법으로 동작하긴 하나, 몇몇 문제가 즉각 눈에 띄게 된다.&lt;br /&gt;

&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;database 접속 parameter가 hard-coding되어 있다. 이상적으로는 이런 parameter등은 django configuration에 저장되어야 한다.&lt;/LI&gt;
&lt;LI&gt;약간의 보일러판과 같은 코드가 포함되어 있다. 이는 접속, cursor 생성, statement 실행, 그리고 connection을 닫는것을 의미한다. 이상적으로 우리가 할 일이란 우리가 원하는 어떠한 결과를 구할지를 지정하는 것이다.&lt;/LI&gt;
&lt;LI&gt;MySQL에 묶여 있다. 만약 MySQL에서 PostgreSQL로 변경하는 경우, database adaptor(psycopg, MySQLdb)가 달라지게 된다. 그러면 접속 parameter는 변경하게 되고, SQL statement의 본질에 의존하게 되어 SQL를 다시 써야할 지도 모른다. 이상적으로 사용할 database 서버는 추상적(abstracted)이어야 하고, 그래서 같은 곳에서 database server는 변경가능해야 한다.&lt;/LI&gt;&lt;/UL&gt;예상했듯이, django의 database 계층은 이러한 문제를 해결하는데 그 목표를 두고 있다. 아래는 이전 예제에 대해 django의 database API를 이용한 것이다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 386px; HEIGHT: 146px&quot; class=python rows=5 cols=39 name=code&gt;from django.shortcuts import render_to_response
from mysite.books.models import Book

def book_list(request):
	books = Book.objects.order_by('name')	return render_to_response('book_list.html', {'books': books})&lt;/TEXTAREA&gt;&lt;br /&gt;
본 code에 대해서는 추후 설명할 것이다. 우선 느껴보기 바란다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;MTV(혹은 MVC) 개발 패턴&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;code를 뒤지기 전에 우선 database 중심의 django web application의 design에 대한 전반적인 설명이 필요하다.&lt;br /&gt;
&lt;br /&gt;이전 chapter에서 언급하였듯이, django는 loose coupling을 장려하도록 설계되었고, code 조각의 구별이 엄격하게 이뤄지도록 한다. 만약 이러한 철학을 따른다면, 특정 조각은 다른 조각의 영향없이 변경이 쉽게 이뤄지도록 해야 한다는 것이다. 예들 들어 view 함수에서 template system을 사용함으로써 표현 logic으로 부터 bussiness logic을 분리하는 것이 중요하다고 논하였다. database 계층으로 data 접근 logic에서도 동일한 철학을 적용하도록 한다.&lt;br /&gt;
&lt;br /&gt;data 접근 logic, bussiness logic, 그리고 표현 logic과 같은 3개의 조각은 함께 software architecture에서 &lt;EM&gt;Model-View-Controller&lt;/EM&gt;(MVC) 패턴으로 불려진다. 이 패턴에서, &quot;Model&quot;은 data 접근 계층, &quot;View&quot;는 무었을 어떻게 표시할지를 결정하는 시스템의 일부, 그리고 &quot;Controller&quot;는 사용자 필요시 model을 접근하고 사용자 input에 의존하여 어떤 view를 사용할지를 결정하는 시스템의 일부를 언급한다.&lt;br /&gt;
&lt;br /&gt;django는 MVC 패턴을 MVC framwork이라고 불리는 것으로 근접하게 따르고 있다. M, V, 그리고 C를 나누어 간략히 설명하면 다음과 같다.&lt;br /&gt;

&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;M, data 접근 부분으로, 본&amp;nbsp;chapter에서 설명된 django의 database 계층에 의해 처리된다.&lt;/LI&gt;
&lt;LI&gt;V, 어떤 그리고 어떻게 출력할지에 대한 부분으로 view와 template에 의해 처리된다.&lt;/LI&gt;
&lt;LI&gt;C, 사용자 input에 의존하여 view를 선택하는 부분으로, URLconf에 의해 따르고 주어진 URL에 대해 적당한 python 함수를 호출하는 것으로 framework에 의해 처리된다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&quot;C&quot;는 framework 그 자체에 의해 처리되기 때문에, django에서 대부분의 신나는 일은 model, template, 그리고 view에서 이뤄진다. 그래서 MTV framework이라 불리기도 한다. MTV 개발 패턴은 다음과 같다.&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;M은 &quot;Model&quot;을 의미하는 것으로, data 접근 계층이다. 이것은 data의 모든것을 다룬다.&lt;br /&gt;
; 어떻게 접근할지, 어떻게 입증(validate)할지, 어떤 행동을 가질지, 그리고 data간의 관계에 대해서.&lt;/LI&gt;
&lt;LI&gt;T는 &quot;Template&quot;를 의미하는 것으로, 표현(presentation) 계층이다. 이것은 표현과 관계된 결정을 다룬다.&lt;br /&gt;
; web page 혹은 다른 종류의 문서를 어떻게 표현할 것인지.&lt;/LI&gt;
&lt;LI&gt;V는 &quot;View&quot;를 의미하는 것으로, bussiness logic 계층을 의미하는 것으로, model 접근을 포함하고 저합한 template(들)을 따른다. model과 template간의 중간 다리 역할이라고 생각하면 된다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Ruby on Rails와 같은 MVC web 개발 framework에 친숙하다면, django view를 &quot;controller&quot;, django template를 &quot;view&quot;라고 간주할 수 있다. 이와 같이 MVC의 다른 해석에 따른 혼란은 불행한 일이다. django의 MVC에 대한 해석은, &quot;view&quot;는 사용자에게게 표현될 data를 기술(describe)하고, &lt;EM&gt;어떤&lt;/EM&gt; data가 표현되더라도 &lt;EM&gt;어떻게 &lt;/EM&gt;그 data가 보여질지는 꼭 필요하지는 않다. 이에 비해 Ruby on Rails나 비슷한 framwork에서 controller의 작업은 어떤 data가 사용자에게 표현될지 결정을 포함하는데, &lt;EM&gt;어떤&lt;/EM&gt; data가 표현될지를 결정하기 보다는 view가 &lt;EM&gt;어떻게 &lt;/EM&gt;보여지는지를 엄격히 한다.&lt;br /&gt;
&lt;br /&gt;어떤 해석도 다른것보다 더 &quot;정확&quot;할 순 없다. 그 이면의 개념을 이해하는 것이 가장 중요하다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;database 설정하기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;앞선 철학에 대해 염두한채, django의 database 계층에 대해 알아보자. 우선 몇몇 초기 설정에 대한 주의가 필요하다. 우리는 어떤 database server를 사용하고 접속할지에 대해 django에 알려줘야 한다.&lt;br /&gt;
&lt;br /&gt;우리는 database server를 설치, 활성화하고 CREATE DATABASE statement등으로 그것 내부에 database를 생성했다고 가정한다. 만일 SQLite를 사용하고 있다면, data 저장을 filesystem의 단일 file로 하기 때문에, 설치과정은 필요없다.&lt;br /&gt;
&lt;br /&gt;이전장의 TEMPLATE_DIRS 처럼, database 설정은 settings.py에서 기본적으로 할 수 있다. 해당 file을 편집해보면 아랫부분을 찾을 수 있다.&lt;br /&gt;
&lt;PRE class=python name=&quot;code&quot;&gt;DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': '',                      # Or path to database file if using sqlite3.
        'USER': '',                      # Not used with sqlite3.
        'PASSWORD': '',                  # Not used with sqlite3.
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}&lt;/PRE&gt;&lt;br /&gt;
이에 대한&amp;nbsp;설명은 아래와 같다. 
&lt;P&gt;&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;(&lt;FONT color=#ff8b16&gt;역자주&lt;/FONT&gt;) django 1.2 부터 &lt;A title=&quot;[https://docs.djangoproject.com/en/dev/releases/1.2/#support-for-multiple-databases]로 이동합니다.&quot; href=&quot;https://docs.djangoproject.com/en/dev/releases/1.2/#support-for-multiple-databases&quot; target=_blank&gt;multiple database connection&lt;/A&gt;(&lt;A title=&quot;[https://docs.djangoproject.com/en/dev/topics/db/multi-db/]로 이동합니다.&quot; href=&quot;https://docs.djangoproject.com/en/dev/topics/db/multi-db/&quot; target=_blank&gt;상세정보&lt;/A&gt;)가 추가되었는데,&amp;nbsp;'default' : 는 이에 해당되는 것으로, 기본 database 설정을 의미한다. (원본글은 django 1.0인데, 이때의 django는 1 project에 1 database 였다)&lt;/LI&gt;
&lt;LI&gt;DATABASE_ENGINE은 django에서 사용할 database 종류를 기술한다. 만약 django로 database를 사용하고자 한다면, DATABASE_ENGINE은 아래표의 값중 하나로 선택되어야 한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#eaf4cf&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;33%&quot;&gt;설정값(django.db.backends.*)&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;33%&quot;&gt;Database&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;33%&quot;&gt;필요한 adapter&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;33%&quot;&gt;postgresql&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;33%&quot;&gt;PostgreSQL&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;33%&quot;&gt;&lt;A title=&quot;[http://www.djangoproject.com/r/python-pgsql/1/]로 이동합니다.&quot; href=&quot;http://www.djangoproject.com/r/python-pgsql/1/&quot; target=_blank&gt;psycopg version 1.x&lt;/A&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;33%&quot;&gt;postgresql_psycopg2&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;33%&quot;&gt;PostgreSQL&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;33%&quot;&gt;&lt;A title=&quot;[http://www.djangoproject.com/r/python-pgsql/]로 이동합니다.&quot; href=&quot;http://www.djangoproject.com/r/python-pgsql/&quot; target=_blank&gt;psycopy_verison 2.x&lt;/A&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;33%&quot;&gt;mysql&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;33%&quot;&gt;MySQL&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;33%&quot;&gt;&lt;A title=&quot;[http://www.djangoproject.com/r/python-mysql/]로 이동합니다.&quot; href=&quot;http://www.djangoproject.com/r/python-mysql/&quot; target=_blank&gt;MySQLdb&lt;/A&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;33%&quot;&gt;sqlite3&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;33%&quot;&gt;SQLite&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;33%&quot;&gt;(python 2.4 이하)&lt;A title=&quot;[http://www.djangoproject.com/r/python-sqlite/]로 이동합니다.&quot; href=&quot;http://www.djangoproject.com/r/python-sqlite/&quot; target=_blank&gt;pysqlite&lt;/A&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;33%&quot;&gt;oracle&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;33%&quot;&gt;Oracle&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;33%&quot;&gt;&lt;A title=&quot;[http://www.djangoproject.com/r/python-oracle/]로 이동합니다.&quot; href=&quot;http://www.djangoproject.com/r/python-oracle/&quot; target=_blank&gt;cx_Oracle&lt;/A&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;당신이 어떤 database를 사용하더라도 그에 해당되는 adapter를 다운로드, 그리고 설치해야 한다.&amp;nbsp;각각은 web을 통해 무료로 설치할 수 있다. 만약 linux 시스템이라면, package 배포 도구는 좀더 편한 package를 설치하도록 유도할 것이다.&lt;br /&gt;
예)&lt;br /&gt;
DATABASE_ENGINE='postgresql_psycopg2'&lt;/LI&gt;
&lt;LI&gt;DATABASE_NAME은 django에서 사용될 database 이름을 기술한다.&lt;br /&gt;
예)&lt;br /&gt;
DATABASE_NAME='mydb'&lt;br /&gt;
만일 SQLite를 사용한다면, database가 사용하는 filesystem 상의 fullpath를 기술하면 된다.&lt;br /&gt;
예)&lt;br /&gt;
DATABASE_NAME='/home/django/mydata.db'&lt;br /&gt;
만일 SQLite database를 사용한다면, 위 예에서는 /home/django 경로를 사용할 것이다.&lt;br /&gt;
참고로, sqlite3를 사용한다면, settings.py에,&lt;br /&gt;
&lt;PRE class=python name=&quot;code&quot;&gt;import os
...
SITE_ROOT = os.path.dirname(os.path.realpath(__file__))
...
'NAME': os.path.join(SITE_ROOT, 'db') + '/development.db',
...&lt;/PRE&gt;&lt;/LI&gt;
&lt;LI&gt;와&amp;nbsp;같으면,&amp;nbsp;project 경로 하부의 db 경로의 development.db 파일을 남긴다.&amp;nbsp;단, 만일 db&amp;nbsp;경로가 없다면 오류를 리턴한다.&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;DATABASE_USER는 django로 하여금 database에 접속할 username을 기술하도록 한다. 만약 SQLite를 사용한다면 비워두면 된다.&lt;/LI&gt;
&lt;LI&gt;DATABASE_PASSWORD는 database에 접속할때 사용할 비밀번호를 의미한다. 만약 SQLite 혹은 비밀번호가 비어있는 경우, 본 값을 비워두면 된다.&lt;/LI&gt;
&lt;LI&gt;DATABASE_HOST는 database에 접속할 host이름을 기술한다. 만약 django가 설치된 시스템인 경우 혹은 SQLite를 사용하는 경우 비워두면 된다.&lt;br /&gt;
MySQL은 좀더 특별한데, MySQL을 사용하고&amp;nbsp;본 값이 '/'로 시작한다면, 지정된 socket으로 unix socket을 경유하여 접속할 것이다. 그 예는 아래와 같다.&lt;br /&gt;
DATABASE_HOST='/var/run/mysql'&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;만약 settings.py를 통해 관련 설정을 저장하였다면 test해보는 것이 좋다. 이를 위해 &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python &lt;/STRONG&gt;manage.py &lt;STRONG&gt;shell&lt;/STRONG&gt;&lt;/FONT&gt;를 mysite의 manage.py가 있는 경우에서 실행한다.&lt;br /&gt;
shell에서 다음과 같이 명령하여 test할 수 있다.&lt;/P&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;C:\django.work\study\mysite&amp;gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;shell&lt;/STRONG&gt;&lt;/FONT&gt;&lt;br /&gt;
Python 2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel)] on&lt;br /&gt;
win32&lt;br /&gt;
Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.&lt;br /&gt;
(InteractiveConsole)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;from django.db import &lt;STRONG&gt;connection&lt;/STRONG&gt;&lt;/FONT&gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;cursor &lt;/FONT&gt;&lt;FONT color=#ff8b16&gt;= connection.&lt;STRONG&gt;cursor&lt;/STRONG&gt;()&lt;br /&gt;
&lt;/FONT&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;만약 database가 성공적으로 설정되었다면, 아무것도 일어나지 않는다. 그렇지 않다면, 무엇이 잘못되었는지에 대해 에러를 표시한다. 아래는 주용한 에러를 표시하였다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#eaf4cf&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;50%&quot;&gt;에러 메시지&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;50%&quot;&gt;해결 방법&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;50%&quot;&gt;Please supply the ENGINE value.&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;50%&quot;&gt;DATABASE_ENGINE setting을 비워두지 말자. 지원되는 database 값을 넣는다.&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;50%&quot;&gt;Environment variable DJANGO_SETTINGS_MODULE is undefined.&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;50%&quot;&gt;python manage.py shell을 이용하여 들어간다.&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;50%&quot;&gt;Error loading ... module: No module named ....&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;50%&quot;&gt;psycopg 혹은 MySQLdb와 같은 적합한 adapter를 찾지 못하였다. 이러한 adapter는 django와 함께 설치되지 않기 때문에, 직접 다운로드하고 설치해야 한다.&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;50%&quot;&gt;... isn't an available database backend&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;50%&quot;&gt;DATABASE_ENGINE setting에 유효한 값을 넣는다.&lt;br /&gt;
혹시 오타가 있지 않았는가?&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;50%&quot;&gt;database ... does not exist&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;50%&quot;&gt;DATABASE_NAME setting에 유효한 database 이름을 넣는다. 혹은 CREATE DATABASE statement을 실행한다.&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;50%&quot;&gt;role ... does not exist&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;50%&quot;&gt;DATABASE_USER setting값을 변경하던지, database에 user를 해당 user를 추가한다.&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;50%&quot;&gt;could not connect server&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;50%&quot;&gt;DATABASE_HOST와 DATABASE_PORT가 정확한지 확인한다. 그리고 해당 server가 동작중인지도 확인한다.&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;
&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;첫번째 app&lt;/SPAN&gt;&lt;br /&gt;
&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
이제 접속하는데까지 확인되었다면, &lt;EM&gt;django app&lt;/EM&gt;을 생성할 차례가 왔다. 이는 단일 python package 내에 존재하는 model과 view code를 포함하는데, 이를 full django application이라 한다.&lt;br /&gt;
&lt;br /&gt;이제 이 용어에 대해 설명할 것인데, 초보자를 위해서이다. chapter 2에서 이미 project를 생성하였다면, &lt;EM&gt;project&lt;/EM&gt;와 &lt;EM&gt;app&lt;/EM&gt;의 차이를 알 수 있겠는가? 그 차이점은 설정 대 code로 설명될 수 있다.&lt;br /&gt;

&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;project는 app에 대한 설정이 추가된, django app의 특정 집합이다. &lt;br /&gt;
&lt;br /&gt;기술적으로, project의 유일한 요구조건이 setting file을 지원하는 것인데, 이는 database 접속 정보, 설치된 app list, 그리고 TEMPLATE_DIR등이 정의되어 있다.&lt;/LI&gt;
&lt;LI&gt;app은 django 기능의 휴대하기(portable) 쉬운 집합이다. 이는 단일 python package에 함께 존재하는 model과 view를 포함하고 있다.&lt;br /&gt;
&lt;br /&gt;예를 들어, django는 댓글 시스템이나 자동화된 관리자 interface와 같은 수많은 app을 포함하고 있다. 이러한 app들의 가장 주목해야할 점은 여러 project를 통해 휴대성과 재사용성이 좋다는 것이다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;이러한 제도안으로&amp;nbsp;당신의 django code를 어떻게 만족시키느냐에 대한 규칙은 그리 엄격하지 않다. 만약 단순한 web site를 구축한다면, 당신은 단일 app을 사용할 것이다. 만약 전자상거래 및 게시판 같은 몇개의 서로 관계가 없는 몇몇의 조각으로 구성된 복잡한 web site를 구성한다면, 미래에 재사용을 위해 app들을 구별하여 분리하기를 원할 것이다.&lt;br /&gt;
&lt;br /&gt;정말, 이전까지 봐왔던 예제와 같이 전혀 app을 생성할 필요성을 못느낄지도 모른다. 이러한 경우, views.py라 불리는 file을 생성하고 URLconf에서 이들을 지명하면 된다. 더이상 필요한 &quot;app&quot;은 없었다.&lt;br /&gt;
&lt;br /&gt;그러나, app 관습(convention)에 따른 요구조건이 하나 있다. : 만약 django database 계층(model)을 사용한다면, django app을 반드시 생성해야 한다. model은 app 내부에 존재한다. 그러므로 model을 작성하려면, 새로운 app을 만들줄 알아야 한다.&lt;br /&gt;
&lt;br /&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;&quot;python &lt;/STRONG&gt;manage.py &lt;STRONG&gt;startapp&lt;/STRONG&gt; books&quot;&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\mydjango\mysite&amp;gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;startapp&lt;/STRONG&gt; books&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\mydjango\mysite&amp;gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/FONT&gt;이 명령은 더이상의 화면 출력은 없으나, books 경로 밑으로 몇몇 파일들을 생성한다.&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile23.uf.tistory.com/original/1825DE414F95F55F11190F&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile23.uf.tistory.com/image/1825DE414F95F55F11190F&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;001.png&quot; height=&quot;116&quot; width=&quot;229&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile1.uf.tistory.com/original/18437D444F95F56C32315E&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile1.uf.tistory.com/image/18437D444F95F56C32315E&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;002.png&quot; height=&quot;128&quot; width=&quot;279&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
이 파일들은 app을 위한 models과 views를 가지고 있다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#fff3b4&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #f3d756 1px solid; BORDER-LEFT: #f3d756 1px solid; BORDER-TOP: #f3d756 1px solid; BORDER-RIGHT: #f3d756 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;역자주)&lt;br /&gt;
&lt;/STRONG&gt;&lt;/FONT&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;startapp&lt;/STRONG&gt; books&lt;/FONT&gt;를 하기위해, manage.py 경로에서 실행하면 위와 같은 directory 구조를 가진다. 원본글은 django 1.4 이전에 나왔기 때문에&amp;nbsp;책내용이 재대로 동작하지 않게 된다.(INSTALLED_APP에서 model을 찾지 못함). 그래서, 아래와 같이,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; C:\mydjango\mysite\mysite&amp;gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;django-admin.py&lt;/STRONG&gt; &lt;STRONG&gt;startapp&lt;/STRONG&gt; books&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; C:\mydjango\mysite\mysite&amp;gt;&lt;br /&gt;
와 같이 하고, 다음과 같은 directory 구조를 가져야 한다.&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile8.uf.tistory.com/original/151C0E3B4F960D641F4CD7&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile8.uf.tistory.com/image/151C0E3B4F960D641F4CD7&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;003.png&quot; height=&quot;132&quot; width=&quot;316&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;models.py와 views.py를 열어보면 models.py에 import와 주석을 제외하고 비어 있음을 확인할 수 있다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;python에서 model 정의하기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;이전 chapter에서&amp;nbsp;&quot;MTV&quot;의 &quot;M&quot;은 &quot;Model&quot;을 의미한다고 하였다. django의 model은 database의 data 설명(description)을 python code로 도식화한 것이다. 그것은 data의 layout로서 SQL의 CREATE TABLE statement와 동일한데 SQL 대신&amp;nbsp;python으로 되어 있다는 차이가 있다. 그리고 database column 정의 그 이상을 포함하고 있다. django model은 무대뒤에서 SQL code를 실행하며, database table의 row를 python data structure로 전달하여 준다. django는 SQL이 처리할 수 없는 고 수준의 개념을 표현하기 위해 model을 사용한다.&lt;br /&gt;
&lt;br /&gt;database에 익숙하다면, 즉시 생각나는것이, SQL 대신 python으로 구성된 model을 정의하는 것이 중복된 일이지 않느냐?일 것이다. django가 그렇게 동작하는 이유는 다음과 같다.&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square; MARGIN-LEFT: 4em&quot;&gt;
&lt;LI&gt;인트로스펙션(&lt;A title=&quot;[http://www.ibm.com/developerworks/kr/library/l-pyint.html]로 이동합니다.&quot; href=&quot;http://www.ibm.com/developerworks/kr/library/l-pyint.html&quot; target=_blank&gt;자기성찰, introspection&lt;/A&gt;)은 부하를 유발하고 불완전하다. 편리한 data 접근 api를 제공하기 위해, django는 &lt;EM&gt;어떻하든지 &lt;/EM&gt;database 계층을 알 필요가 있고 이를 달성하기 위한 2가지 방법을 만들었다. 첫번째로 명시적으로 database를 python으로 설명하고자 함이고, 두번째로 data의 model을 결정하는데 실시간으로 database를 자기성찰하기 위함이다.&lt;br /&gt;
&lt;br /&gt;두번째 방법은 깔끔해 보이는데, table에 대한 metadata는 한 곳에서만 존재하나, 이는 몇가지 문제를 야기한다. 첫번재로 실시간으로 database를 인트로스펙션하는데 부하가 걸린다. 만약 framework이 request때 마다혹은 web server가 초기화될때 마다 database에 대해 인트로스펙션한다면, 받아들일 수 없을 정도의 부하가 발생하게 된다(이러한 부하를 받아들일 수 있다고 몇몇은 믿을 수 있으나, django 개발자는 가능한 줄이기를 목표로 한다). 둘째로 몇몇 MySQL의 옛날 버전과 같은 몇몇 database에서 완벽한 인트로스펙션을 위한 정확한 metadata를 저장하지 않는 경우도 있다.&lt;/LI&gt;
&lt;LI&gt;python을 작성하는 것은 재미있는 일이고 모든것을 모든 것을 python으로 유지하는 것은 당신 두뇌가 &quot;context switch&quot;되는 횟수를 제한한다. 가능한 단일 programming 환경과 사고방식으로 지속하면 그만큼 생산성이 높아진다. SQL을 작성하고, pytho을 작성한뒤 다시 SQL을 작성하는 것이 업무에 차질을 잃으키는 요소가 된다.&lt;/LI&gt;
&lt;LI&gt;database보다 code로 저장된 model을 갖는것이 버전 관리를 보다 쉽게 만든다. 이 방법으로, data layout의 변경 사항에 대해 쉽게 추적할 수 있다.&lt;/LI&gt;
&lt;LI&gt;SQL은 data layout에 대해 meta data의 특정 수준만을 허락한다. 대부분의 database system에서 예를 들어, email address나 URL등의 표현을 위한 특수한 data type을 지원하지 않는다. 이에 반해 django는 지원한다. 높은 수준의 data type의 장점은 높은 생산성과 code의 가독성을 높인다.&lt;/LI&gt;
&lt;LI&gt;SQL은 database system 별로 일관적이지 못하다. 만약 당신이 web application을 배포하려고 한다면, 예를 들어, MySQL, PostgreSQL, 그리고 SQLite를 위한 구별된 CREATE TABLE statement의&amp;nbsp;집합 보다도 당신의 data layout을 설명하는 python module을 배포하는것이 보다 실용적이다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;이러한 접근의 단점은 python code가 database에 실제로 무엇으로 동기화가 이뤄지는제 대해 그 책임을 회피한다는 점이다. django model에 변경을 가하였다면, database를 일관적(consistent)으로 유지하기 위해 database 안으로도 변경이 필요하게 된다. 우리는 이러한 문제를 처리하는데 몇가지 전략을 본 chapter에서 다룰 것이다.&lt;br /&gt;
&lt;br /&gt;마지막으로 기존 database를 인트로스펙팅함에 의해 model을 생성하는 도구를 django가 포함한다는 사실에 주목해야 한다. 이는 이전 과거(legacy) data를 가지고 일어서서 달려나가는데 유용하다. 이는 chapter 18에서 다룰 것이다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;첫 model&lt;/SPAN&gt;&lt;br /&gt;
&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
본 chapter와 다음 chapter에서 진행되는 예제로서, 우리는 기본적인 책(book)/저자(author)/출판사(publisher) layout에 집중할 것이다. 책, 저자, 그리고 출판일간의 개념적 관계(conceptual relationship)은 익히 잘 알려져있고 SQL 관련 서적에서 일반적으로 소개되는 layout이기 때문에 이 예를 사용할 것이다.&amp;nbsp;당신 역시&amp;nbsp;출판사에 의해 생산되고 저자에 의해 씌어진 책을 읽고 있다.&lt;br /&gt;
&lt;br /&gt;우리는 다음과 같이 개념, 필드, 그리고 관계(relation)에 대해 가정한다.&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;저자는 성, 이름, 그리고 email 주소를 가진다.&lt;/LI&gt;
&lt;LI&gt;출판사는 이름, 거리 주소, 도시, 도, 국가, 그리고 web site를 가진다.&lt;/LI&gt;
&lt;LI&gt;책은 제목과 출판일을 가진다. 그리고 하나 이상의 저자(many-to-many relationship)를 가지고 하나의 출판사(one-to-many relationship)를 가진다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;django를 이용한 이러한 database layout을 만드는데 첫번째 할 일은 그것을 python code로 표현하는 일이다. startapp command에 의해 생성된 models.py에 다음과 같이 기입한다.&lt;br /&gt;
&lt;/P&gt;&lt;PRE class=python name=&quot;code&quot;&gt;from django.db import models
class Publisher(models.Model):
	name = models.CharField(max_length=30)
	address = models.CharField(max_length=50)
	city = models.CharField(max_length=60)
	state_province = models.CharField(max_length=30)
	country = models.CharField(max_length=50)
	website = models.URLField()

class Author(models.Model):
	first_name = models.CharField(max_length=30)
	last_name = models.CharField(max_length=40)
	email = models.EmailField()

class Book(models.Model):
	title = models.CharField(max_length=100)
	authors = models.ManyToManyField(Author)
	publisher = models.ForeignKey(Publisher)
	publication_date = models.DateField()&lt;/PRE&gt;기초 닦기 위해 빠른 설명부터 진행한다. 각 model은 django.db.models.Model의 subclass에 의해 표현된다. Model이라는 부모 class는 database와 연동하기 위한 object를 만드는데 필요한 모든 기계적인 부분을 가지고 있다. 그리고 간결한 문법으로 필드 정의를 유도한다. 믿거나 말거나, django로 기본적인 data 접근을 위한 모든 코드가 표기되었다.&lt;br /&gt;
&lt;br /&gt;각 model은 일반적으로 단일 database table에 상응한다고 보면 된다. 그리고 model에 각 속성(attribute)는 column의 이름에 해당된다. 그리고 필드의 type(예, CharField)은 database의 column type(예, varchar)에 대응된다. 예를 들어, Publisher model은 다음과 같은 table과 동일한다. (postgreSQL Create Table 문법)&lt;br /&gt;
&lt;br /&gt;&lt;PRE class=sql name=&quot;code&quot;&gt;BEGIN;
CREATE TABLE &quot;books_publisher&quot; (
    &quot;id&quot; serial NOT NULL PRIMARY KEY,
    &quot;name&quot; varchar(30) NOT NULL,
    &quot;address&quot; varchar(50) NOT NULL,
    &quot;city&quot; varchar(60) NOT NULL,
    &quot;state_province&quot; varchar(30) NOT NULL,
    &quot;country&quot; varchar(50) NOT NULL,
    &quot;website&quot; varchar(200) NOT NULL
)
;
CREATE TABLE &quot;books_author&quot; (
    &quot;id&quot; serial NOT NULL PRIMARY KEY,
    &quot;first_name&quot; varchar(30) NOT NULL,
    &quot;last_name&quot; varchar(40) NOT NULL,
    &quot;email&quot; varchar(75) NOT NULL
)
;
CREATE TABLE &quot;books_book&quot; (
    &quot;id&quot; serial NOT NULL PRIMARY KEY,
    &quot;title&quot; varchar(100) NOT NULL,
    &quot;publisher_id&quot; integer NOT NULL REFERENCES &quot;books_publisher&quot; (&quot;id&quot;) DEFERRABLE INITIALLY DEFERRED,
    &quot;publication_date&quot; date NOT NULL
)
;
CREATE TABLE &quot;books_book_authors&quot; (
    &quot;id&quot; serial NOT NULL PRIMARY KEY,
    &quot;book_id&quot; integer NOT NULL REFERENCES &quot;books_book&quot; (&quot;id&quot;) DEFERRABLE INITIALLY DEFERRED,
    &quot;author_id&quot; integer NOT NULL REFERENCES &quot;books_author&quot; (&quot;id&quot;) DEFERRABLE INITIALLY DEFERRED,
    UNIQUE (&quot;book_id&quot;, &quot;author_id&quot;)
)
;
CREATE INDEX &quot;books_book_publisher_id&quot; ON &quot;books_book&quot; (&quot;publisher_id&quot;);
COMMIT;&lt;/PRE&gt;정말, django는 CREATE TABLE를 자동으로 생성하며 곧 바로 그것을 보게될 것이다.&lt;br /&gt;
&lt;br /&gt;database table당 하나의 class(one-class-per-database-table) 규칙의 예외는 many-to-many relationship인 경우이다. 위 예에서 Book은 authors라 불리는 ManyToManyField를 가지는데, 이러한 하나의 책이 다수의 저자를 기호로 표기한 것이다. 그러나 Book database table은 authors column을 가지지 않는다. django는 추가적인 책에서 저자로 매핑을 처리하는 table(즉, many-to-many 'join table&quot;)을 생성한다.&lt;br /&gt;
&lt;br /&gt;모든 필드의 datatype과 문법은 부록 B를 참고 바란다.&lt;br /&gt;
&lt;br /&gt;마지막으로 우리는 각 model에 대해 명시적인 primary key를 정의하지 않았다. 만약 그것을 알려주지 않았다면, django는 자동으로 id라 불리는 자동으로 증가하는 (auto-incrementing) primary key 필드를 부여한다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;model 설치하기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;우리는 여태껏 code를 작성하였는데, 이제 database의 table을 생성해 보도록 하자. 그러기 위해서는 첫번째로 django project에 이러한 model을 &lt;EM&gt;활성화&lt;/EM&gt;시켜야 한다.&amp;nbsp;이는 setting 파일에 있는 &quot;installed apps&quot; 리스트에 books app을&amp;nbsp;추가하는 것으로 해결된다.&lt;br /&gt;
&lt;br /&gt;settings.py 파일로 돌어와서, INSTALLED_APPS 세팅을 찾아 보자. INSTALLED_APPS는 주어진 project에 어떤 app을 활성화할 것인지를 알려준다. 기본으로 다음과 같은 모양을 가진다.&lt;br /&gt;
&lt;PRE class=python name=&quot;code&quot;&gt;INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Uncomment the next line to enable the admin:
    # 'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',
)&lt;/PRE&gt;임시적으로 위 모든 줄에 대해 #를 추가하여 주석 처리 한다. (이것들은 일반적으로 사용되기 때문에 기본으로 포함되었으나, 이후 chapter에서 설명하도록 한다.) 그릭고, MIDDLEWARE_CLASSES setting도 역시 주석 처리해야 한다.&amp;nbsp;MIDDLEEWARE_CLASSES에 있는 기본값들은 우리가 앞서 주석 처리한 것에 의존성을 가지기 때문이다. 즉, 다음과 같이 수정한다.&lt;br /&gt;
&lt;PRE class=python name=&quot;code&quot;&gt;MIDDLEWARE_CLASSES = (
    #'django.middleware.common.CommonMiddleware',
    #'django.contrib.sessions.middleware.SessionMiddleware',
    #'django.middleware.csrf.CsrfViewMiddleware',
    #'django.contrib.auth.middleware.AuthenticationMiddleware',
    #'django.contrib.messages.middleware.MessageMiddleware',
    # Uncomment the next line for simple clickjacking protection:
    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

INSTALLED_APPS = (
    #'django.contrib.auth',
    #'django.contrib.contenttypes',
    #'django.contrib.sessions',
    #'django.contrib.sites',
    #'django.contrib.messages',
    #'django.contrib.staticfiles',
    # Uncomment the next line to enable the admin:
    # 'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',
    'mysite.books'
)&lt;/PRE&gt;(지난 chapter에서 TEMPLATE_DIRS를 세팅할때 언급했던거 처럼, tuple로 되어 있기 때문에 끝에 ','로 끝을 내야 한다. 덧붙여 말해서 책 저자들은 보통 tuple의 &lt;EM&gt;모든 &lt;/EM&gt;element 뒤에 ','를 붙이기를 선호하는데, 물론 단일 element일 때에도 마찬가지 이다. 이는 ','를 누락시키는 실수를 방지하며, 있더라도 다른 부작용은 없다.)&lt;br /&gt;
&lt;br /&gt;'mysite.books'는 우리가 작동시키려고 하는 books app을 참고한다. INSTALLED_APPS에 있는 각각의 app은 full python path로 표현되어 진다. 그 말인 즉, '.'으로 구별된 packages의 경로로 app package를 선두로 한다.&lt;br /&gt;
&lt;br /&gt;이제 django app은 setting 파일에 의해 활성화 되었고, database table을 생성시켜 보자. 우선, 첫번째로 아래를 실행하여 model을 검증(validate)해 보자.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\mydjango\mysite&amp;gt;&lt;FONT color=#ff8b16&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; &lt;/FONT&gt;manage.py &lt;STRONG&gt;validate&lt;/STRONG&gt;&lt;br /&gt;
&lt;/FONT&gt;0 errors found&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\mydjango\mysite&amp;gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;validate 명령은 문법과 로직의 옳고 그름을 판별한다. 만약 문제가 없다면 0 error found를 알려준다. 그렇지 않다면, model code가 정확한지 확인해 볼 필요가 있다.&amp;nbsp;출력된 error 메시지가 도움을 줄 것이다.&lt;br /&gt;
&lt;br /&gt;model 작업시 문제가 있다고 생각된다면, 언제든지 &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;validate&lt;/STRONG&gt;&lt;/FONT&gt;를 호출하기 바란다. 그것은 통상적인 model 문제를 잡아낼 것이다.&lt;br /&gt;
&lt;br /&gt;만일 model에 문제가 없다면, 다음을 실행하여 django로 하여금 books app에 있는 model를 위해 CREATE TABLE&amp;nbsp;statement를 실행하도록 한다. 해당 명령을 실행하면 아래와 같은 결과를 얻을 수 있다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\mydjango\mysite&amp;gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;sqlall&lt;/STRONG&gt; books&lt;/FONT&gt;&lt;br /&gt;
BEGIN;&lt;br /&gt;
CREATE TABLE &quot;books_publisher&quot; (&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;id&quot; integer NOT NULL PRIMARY KEY,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;name&quot; varchar(30) NOT NULL,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;address&quot; varchar(50) NOT NULL,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;city&quot; varchar(60) NOT NULL,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;state_province&quot; varchar(30) NOT NULL,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;country&quot; varchar(50) NOT NULL,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;website&quot; varchar(200) NOT NULL&lt;br /&gt;
)&lt;br /&gt;
;&lt;br /&gt;
CREATE TABLE &quot;books_author&quot; (&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;id&quot; integer NOT NULL PRIMARY KEY,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;first_name&quot; varchar(30) NOT NULL,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;last_name&quot; varchar(40) NOT NULL,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;email&quot; varchar(75) NOT NULL&lt;br /&gt;
)&lt;br /&gt;
;&lt;br /&gt;
CREATE TABLE &quot;books_book_authors&quot; (&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;id&quot; integer NOT NULL PRIMARY KEY,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;book_id&quot; integer NOT NULL,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;author_id&quot; integer NOT NULL REFERENCES &quot;books_author&quot; (&quot;id&quot;),&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; UNIQUE (&quot;book_id&quot;, &quot;author_id&quot;)&lt;br /&gt;
)&lt;br /&gt;
;&lt;br /&gt;
CREATE TABLE &quot;books_book&quot; (&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;id&quot; integer NOT NULL PRIMARY KEY,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;title&quot; varchar(100) NOT NULL,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;publisher_id&quot; integer NOT NULL REFERENCES &quot;books_publisher&quot; (&quot;id&quot;),&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;publication_date&quot; date NOT NULL&lt;br /&gt;
)&lt;br /&gt;
;&lt;br /&gt;
CREATE INDEX &quot;books_book_22dd9c39&quot; ON &quot;books_book&quot; (&quot;publisher_id&quot;);&lt;br /&gt;
COMMIT;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\mydjango\mysite&amp;gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;다음 사항을 주목하자.&lt;br /&gt;

&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;table 이름은 자동으로 생성되고, 이는 app 이름(books)과 소문자 model 이름(publisher, book, 그리고 author)의 조합으로 이뤄진다. 이런 동작을 무시하려면 부록 B를 참고하시오.&lt;/LI&gt;
&lt;LI&gt;이전에 언급했듯이, django는 각 table에 대해 id field라는 자동으로 pimary key를 추가한다. 이또한 무시할 수 있다.&lt;/LI&gt;
&lt;LI&gt;관례에 따라, django는 &quot;_id&quot;가 추가된 foreign key를 추가한다. 이것은 무시할 수 있다.&lt;/LI&gt;
&lt;LI&gt;foreign key 관계는 명시적인 REFERENCES statement를 이용한다.&lt;/LI&gt;
&lt;LI&gt;CREATE TABLE statement는 사용하는 database에 딱 맞춰 돌아가게 되는데, database 지정 field type(database-specific field type), 예를 들어 auto_increment(MySQL), serial(PostgreSQL) 혹은 integer primary key(SQLite)등이 자동으로 처리되어 진다. column 이름의 따옴표 처리도 그러하다(' 혹은 &quot;). 위 예는 SQLite의 예제이다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;sqlall 명령은 실제로는 database를 건드리는 table 생성이나 기타 다른것들을 실행하진 않는다. 단지 django에서 어떤 SQL를 실행할지에 대해 출력할 뿐이다. 원한다면, 이 SQL을 database client에 copy-paste할 수 있고, 혹은 unix pipe로 직접 호출할 수 있다(예, python manage.py sqlall books | psql mydb). 그러나, django는 SQL을 database에 commit하는 보다 쉬운 방법을 syncdb 명령을 이용하여 제공한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;C:\mydjango\mysite&amp;gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;syncdb&lt;/STRONG&gt;&lt;/FONT&gt;&lt;br /&gt;
Creating tables ...&lt;br /&gt;
Creating table books_publisher&lt;br /&gt;
Creating table books_author&lt;br /&gt;
Creating table books_book_authors&lt;br /&gt;
Creating table books_book&lt;br /&gt;
Installing custom SQL ...&lt;br /&gt;
Installing indexes ...&lt;br /&gt;
Installed 0 object(s) from 0 fixture(s)&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;syncdb 명령은 database에게 당신 model을 간단히 &quot;동기화&quot;하는 일을 한다. INSTALLED_APPS 세팅에 있는 각각의 app에 대해 모든 model을 보고, 기존에 table이 있는지 확인하고, 그리고 존재하지 않다면 table을 생성한다. syncdb는 model의 삭제나 변경사항에 대해 동기화하진 &lt;EM&gt;않는다&lt;/EM&gt;. model을 변경하거나 삭제하는 경우, 혹은 database를 update하는 경으 syncdb는 그에 대해서는 처리하지 않는다.(자세한건 이후의 내용 참고)&lt;br /&gt;
&lt;br /&gt;만약 &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;syncdb&lt;/STRONG&gt;&lt;/FONT&gt;를 다시 실행한다면, 어떤일도 발생하지 않는데, INSTALLED_APPS에 어떤 app도 추가되거나 books app에 어떤 model도 추가되지 않았기 때문이다. 그러므로, &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;syncdb&lt;/STRONG&gt;&lt;/FONT&gt;는 항상 안전하다. 즉, 어떠한 손실도 잃으키지 않는다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;C:\mydjango\mysite&amp;gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;syncdb&lt;/STRONG&gt;&lt;br /&gt;
&lt;/FONT&gt;Creating tables ...&lt;br /&gt;
Installing custom SQL ...&lt;br /&gt;
Installing indexes ...&lt;br /&gt;
Installed 0 object(s) from 0 fixture(s)&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;만약 흥미를 느꼈다면, django가 생성한 database table을 보거나 database의 command-line client에 들어가 보기 바란다. command-line client(예, PostgreSQL인 경우 psq)를 수동으로 실행할 수 있고, &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;dbshell&lt;/STRONG&gt;&lt;/FONT&gt;도 가능하다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\mydjango\mysite&amp;gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;dbshell&lt;/STRONG&gt;&lt;br /&gt;
&lt;/FONT&gt;'sqlite3'은(는) 내부 또는 외부 명령, 실행할 수 있는 프로그램, 또는&lt;br /&gt;
배치 파일이 아닙니다.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\mydjango\mysite&amp;gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;dbshell&lt;/STRONG&gt;&lt;br /&gt;
&lt;/FONT&gt;SQLite version 3.7.11 2012-03-20 11:35:50&lt;br /&gt;
Enter &quot;.help&quot; for instructions&lt;br /&gt;
Enter SQL statements terminated with a &quot;;&quot;&lt;br /&gt;
sqlite&amp;gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;즉, 위 명령은 sqlite3.exe를 실행해 주는데, &lt;A href=&quot;http://www.sqlite.org/download.html&quot;&gt;http://www.sqlite.org/download.html&lt;/A&gt;를 통해 sqlite3.exe를 C:\Windows\System32에 복사해 주면 자동으로 해당 db의 command-line client(예, sqlite3.exe)를 실행해 준다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;기본적인 data 접근&lt;/SPAN&gt;&lt;br /&gt;
&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
일단 model을 생성하였다면, django는 자동으로 이러한 model을 가지고 작업할 높은 수준의 python api를 자동으로 제공한다. &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;shell&lt;/STRONG&gt;&lt;/FONT&gt;을 통해 다음을 실행해 보자.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;C:\mydjango\mysite&amp;gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;shell&lt;/STRONG&gt;&lt;br /&gt;
&lt;/FONT&gt;Python 2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel)] on&lt;br /&gt;
win32&lt;br /&gt;
Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.&lt;br /&gt;
(InteractiveConsole)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;from&lt;/STRONG&gt; mysite.books.models &lt;STRONG&gt;import&lt;/STRONG&gt; Publisher&lt;br /&gt;
&lt;/FONT&gt;&amp;gt;&amp;gt;&amp;gt; p1 = &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;Publisher&lt;/STRONG&gt;&lt;/FONT&gt;(name='Apress', address='2855 Telegraph Avenue',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; city='Berkeley', state_province='CA', country='U.S.A.',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; website='http://www.apress.com/')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; p1.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;save&lt;/FONT&gt;&lt;/STRONG&gt;()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; p2 = &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;Publisher&lt;/FONT&gt;&lt;/STRONG&gt;(name=&quot;O'Reilly&quot;, address='10 Fawcett St.',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; city='Cambridge', state_province='MA', country='U.S.A.',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; website='http://www.oreilly.com/')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; p2.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;save&lt;/FONT&gt;&lt;/STRONG&gt;()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; publisher_list = &lt;FONT color=#ff8b16&gt;Publisher.&lt;STRONG&gt;object.all&lt;/STRONG&gt;&lt;FONT color=#ffffff&gt;()&lt;/FONT&gt;&lt;/FONT&gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; publisher_list&lt;br /&gt;
[&amp;lt;Publisher: Publisher object&amp;gt;, &amp;lt;Publisher: Publisher object&amp;gt;]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;이 몇줄의 코드로 짧막한 기능을 수행한다. 요점은 다음과 같다.&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;우선, Publisher model class를 import한다. 이는 publisher가 포함하는 database table과 상호 동작을 가능하게 한다.&lt;/LI&gt;
&lt;LI&gt;Publisher object를 생성하고, name, address, ...과 같은 값으로 초기화한다.&lt;/LI&gt;
&lt;LI&gt;database에 object를 저장하기 위해, save() method를 호출한다. django에서는 INSERT statement를 내부적으로 실행한다.&lt;/LI&gt;
&lt;LI&gt;database로 부터 publisher를 구하기 위해 Publisher.object 속성을 이용한다. 이는 publisher의 모든 집합이라고 생각하면 된다.&amp;nbsp;&lt;EM&gt;모든&lt;/EM&gt; Publisher object의 list를 가져오기 위해, Publisher.objects.all()을 사용하였다. django는 내부적으로 SELECT statement를 사용한다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;django model api를 사용하여 object를 생성한다면, django는 save() method를 호출할 때 까지 dattabase에 object를 저장하지 않는다.&lt;br /&gt;
&lt;br /&gt;만약 database에 한번의 step으로 object를 생성하고 바로 저장하려면, objects.create() method를 사용한다. 다음은 그 예이다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; p1 = &lt;FONT color=#ff8b16&gt;Publisher.&lt;STRONG&gt;objects&lt;/STRONG&gt;.&lt;STRONG&gt;create&lt;/STRONG&gt;&lt;/FONT&gt;(name='Apress',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; address='2855 Telegraph Avenue',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; city='Berkeley', state_province='CA', country='U.S.A.',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; website='http://www.apress.com/')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; p2 = &lt;FONT color=#ff8b16&gt;Publisher.&lt;STRONG&gt;objects&lt;/STRONG&gt;.&lt;STRONG&gt;create&lt;/STRONG&gt;&lt;/FONT&gt;(name=&quot;O'Reilly&quot;,&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; address='10 Fawcett St.', city='Cambridge',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; state_province='MA', country='U.S.A.',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; website='http://www.oreilly.com/')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; publisher_list = &lt;FONT color=#ff8b16&gt;Publisher.&lt;STRONG&gt;objects.all&lt;/STRONG&gt;&lt;/FONT&gt;()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; publisher_list&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;자연스럽게 django database api로 많은 것을 할수 있으나, 몇몇 골칫거리를 처리해야 한다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;model의 문자열 표현 추가하기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;앞서 publisher의 list를 출력할 때, 다음과 같이 알아내기 힘든 형태로 표시되었다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;[&amp;lt;Publisher: Publisher object&amp;gt;, &amp;lt;Publisher: Publisher object&amp;gt;]&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;__unicode__() method를 Publisher class에 호출하면 쉽게 표시할 수 있다. __unicode__() method는 python으로 하여금 해당 object의 &quot;unicode&quot; 표현을 출력하도록 도와준다. 다음과 같이 __unicode__() method를 추가하여 본다.&lt;br /&gt;
&lt;br /&gt;&lt;/P&gt;&lt;PRE class=python name=&quot;code&quot;&gt;from django.db import models

class Publisher(models.Model):
	name = models.CharField(max_length=30)
	address = models.CharField(max_length=50)
	city = models.CharField(max_length=60)
	state_province = models.CharField(max_length=30)
	country = models.CharField(max_length=50)
	website = models.URLField()
	
	def __unicode__(self):
		return self.name

&lt;/FONT&gt;class Author(models.Model):
	first_name = models.CharField(max_length=30)
	last_name = models.CharField(max_length=40)
	email = models.EmailField()
	
	def __unicode__(self):
		return u'%s %s' % (self.first_name, self.last_name)

class Book(models.Model):
	title = models.CharField(max_length=100)
	authors = models.ManyToManyField(Author)
	publisher = models.ForeignKey(Publisher)
	publication_date = models.DateField()
	
	def __unicode__(self):
		return self.title&lt;/PRE&gt;위에서 볼 수 있듯이, __unicode__() method는 한 object의 표현을 전달하기 위해 필요한 것들을 수행한다. 여기서 Publisher와 Book을 위한 __unicode__() method는 단지 object의 name과 title을 각각 전달한다. 단, Author는 조금 복잡한데, 공백으로 구별된 first_name과 last_name을 함께 표기한다.&lt;br /&gt;
&lt;br /&gt;__unicode__()의 유일한 요구사항은, Unicode object를 리턴해야 한다는 점이다. 만약 __unicode__()가 Unicode object를 전달하지 않는다면(예를 들어, 정수), python은 &quot;coercing to Unicode: need string or buffer, int found&quot; 형태의 TypeError 메시지의 예외가 발생하게 된다.&lt;br /&gt;
&lt;br /&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#ffffff&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;100%&quot;&gt;Unicode object&lt;br /&gt;
&lt;br /&gt;Unicode object는 뭘까?&lt;br /&gt;
&lt;br /&gt;당신은 Unicode object를 Latin 계열의 억양이 표시된 문자에서부터 동그랗게 말린 따움표와 잘 알려지지 않은 기호에 까지 수백만개 이상의&amp;nbsp;다른 종류의 문자를 를 처리할 수 있는 python string으로 생각할 수 있다.&lt;br /&gt;
&lt;br /&gt;보통(Normal) python string은 &lt;EM&gt;인코드(encode)&lt;/EM&gt;되어 있는데, 이는 ASCII, ISO-8859-1 혹은 UTF-8과 같은 encode를 사용한다고 보면 된다. 만약 당신이&amp;nbsp;0-9, A-Z와 같은 표준 128 ASCII 문자등을 저장하려 한다면, 당신 string이 사용하는 encoding을 사용하는지에 대해 함께 기록해야 한다. 그렇지 않다면, 출력할 때 얼그러지게 나타나게 된다. 임의의 encoding으로 저장한 data를 다른 encoding으로 조합을 시도할 때 혹은 특정 encoding을 가정한 application에서 출력을 시도할 때 문제가 발생하게 된다. 우리 모두 &quot;??? ??????&quot; 혹은 이상한 문자로 채워진 e-mail과 web page를 본적이 있을 것이다. 이는 encoding 문제가 있음을 시사한다.&lt;br /&gt;
&lt;br /&gt;Unicode object는 그자체가 encoding이 없다. 즉, 알려진 &quot;Unicode&quot;로 불리는&amp;nbsp;일정하고 전세계적인 문자열 집합을 사용한다. python으로 unicode object를 사용하게 되면 encoding 이슈없이 안전하게 섞거나 매치할 수 있다.&lt;br /&gt;
&lt;br /&gt;django는 Unicode object를 framework 구석 구석 사용한다. Model object는 Unicode object를 전달받고, Unicode data로 view는 상호동작하게 되고, template는 Unicode로 render한다. 일반적으로 당신의 encoding이 맞다고 확신하는데 아무런 걱정을 할 필요는 없다.&lt;br /&gt;
&lt;br /&gt;이는 &lt;EM&gt;매우&lt;/EM&gt; 높은 수준이고, Unicode object의 개념을 너무 단순화시겼다. 그리고 &lt;A title=&quot;[http://www.joelonsoftware.com/articles/Unicode.html]로 이동합니다.&quot; href=&quot;http://www.joelonsoftware.com/articles/Unicode.html&quot; target=_blank&gt;여기&lt;/A&gt;를 통해 좀더 자세히 학습할 수 있다.&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;
__unicode__() 추가로 인해 변경 사항을 적용하려면, python shell을 다시 시작해야 한다. 이제 Publisher object는 훨씬 이해하기가 쉽다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;C:\mydjango\mysite&amp;gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;shell&lt;/STRONG&gt;&lt;br /&gt;
&lt;/FONT&gt;Python 2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel)] on&lt;br /&gt;
win32&lt;br /&gt;
Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.&lt;br /&gt;
(InteractiveConsole)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;from&lt;/STRONG&gt; books.models &lt;STRONG&gt;import&lt;/STRONG&gt; Publisher&lt;br /&gt;
&lt;/FONT&gt;&amp;gt;&amp;gt;&amp;gt; publisher_list = &lt;FONT color=#ff8b16&gt;Publisher.objects.all()&lt;/FONT&gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; publisher_list&lt;br /&gt;
[&amp;lt;Publisher: Apress&amp;gt;, &amp;lt;Publisher: O'Reilly&amp;gt;]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;__unicode__() method를 정의한 model을 확인해 볼 필요가 있다. interactive interpreter를 사용할 때 뿐만 아니라 출력이 필요한 object에게도 __unicode__()를 통해 출력을 사용할 수 있다.&lt;br /&gt;
&lt;br /&gt;마지막으로 __unicode__()는 model에게 &lt;EM&gt;행위(behavior)&lt;/EM&gt;를 추가하는 좋은 예제가 된다. django model은 하나의 object에 대해 database table layout 그 이상을 기술한다. 또한 그것을 어떻게 할 것인지에 대한 기능도 기술할 수 있다. __unicode__()는 이러한 기능에 대한 예인데, 이는 그 자신을 어떻게 출력할 것인지를 알게 한다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;data 삽입과 업데이트&lt;/SPAN&gt;&lt;br /&gt;
&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
여기까지 봐 왔다면, database에 row를 삽입하기 위해서, model instance를 argument를 이용하여 생성하였다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; p = &lt;FONT color=#ff8b16&gt;Publisher&lt;/FONT&gt;(name='Apress',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; address='2855 Telegraph Ave.',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; city='Berkeley',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; state_province='CA',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; country='U.S.A.',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; website='http://www.apress.com/')&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;앞서 설명한바 같이 database를 건드리지 &lt;EM&gt;않는&lt;/EM&gt; 초기화 행동이다. save()를 호출할 때 까지 database로 저장되지 않는다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;p.&lt;STRONG&gt;save&lt;/STRONG&gt;&lt;FONT color=#ffffff&gt;()&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;다음과 같은 SQL로 번역이 가능하다.&lt;br /&gt;
&lt;PRE class=sql name=&quot;code&quot;&gt;INSERT INTO books_publisher
    (name, address, city, state_province, country, website)
VALUES
    ('Apress', '2855 Telegraph Ave.', 'Berkeley', 'CA',
     'U.S.A.', 'http://www.apress.com/');&lt;/PRE&gt;Publisher model은 id라는 자동으로 증가하는 primary key를 사용하기 때문에, save() 호출은 더 많은 일을 수행하게 된다. 해당 record를 위해 primary key 값을 계산하고 instance에 id 속성을 세팅한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; p = &lt;FONT color=#ff8b16&gt;Publisher&lt;/FONT&gt;(name='Apress',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; address='2855 Telegraph Ave.',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; city='Berkeley',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; state_province='CA',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; country='U.S.A.',&lt;br /&gt;
...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; website='http://www.apress.com/')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; p.&lt;FONT color=#ff8b16&gt;id&lt;/FONT&gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; p.&lt;FONT color=#ff8b16&gt;save&lt;/FONT&gt;()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; p.&lt;FONT color=#ff8b16&gt;id&lt;/FONT&gt;&lt;br /&gt;
5&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; p.&lt;FONT color=#ff8b16&gt;save&lt;/FONT&gt;()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; p.&lt;FONT color=#ff8b16&gt;id&lt;/FONT&gt;&lt;br /&gt;
5&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;연속적인 save() 호출은 새로운 record 생성없이 제자리에 해당 record를 저장하게 된다(SQL에서&amp;nbsp;INSERT 대신 UPDATE statement).&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; p.&lt;FONT color=#ff8b16&gt;name &lt;/FONT&gt;= 'Apress Publishing'&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; p.&lt;FONT color=#ff8b16&gt;save&lt;/FONT&gt;()&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;이 save는 다음의 SQL 결과와 같다.&lt;br /&gt;
&lt;PRE class=sql name=&quot;code&quot;&gt;UPDATE books_publisher SET
    name = 'Apress Publishing',
    address = '2855 Telegraph Ave.',
    city = 'Berkeley',
    state_province = 'CA',
    country = 'U.S.A.',
    website = 'http://www.apress.com'
WHERE id = 52;&lt;/PRE&gt;field의 모든것이 updated되는데, 변경된 하나만 시도 되는것이 아니다. application에 따라 이는 race condition을 유발할 수 있다. 아래 &quot;하나의 statement로 여러개의 object 업데이트하기&quot;에서 조금 다른 다음과 같은 query를 하는 방법이 설명된다.&lt;br /&gt;
&lt;PRE class=sql name=&quot;code&quot;&gt;UPDATE books_publisher SET
    name = 'Apress Publishing'
WHERE id=52;&lt;/PRE&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;Object 선택하기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;database record를 생성하고 업데이트하는 방법을 아는 것은 필수적이지만, 당신이 만들 web application은 새로운 하나를 만드는것 보다 기존의 object의 query가 훨씬더 자주있을 것이다. 여태껏 주어진 model에 대해 모든 record를 받는것만 확인해왔다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;all&lt;/STRONG&gt;&lt;/FONT&gt;()&lt;br /&gt;
[&amp;lt;Publisher: Apress&amp;gt;, &amp;lt;Publisher: O'Reilly&amp;gt;]&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;이는 다음과 같이 SQL로 번역된다.&lt;br /&gt;
&lt;PRE class=sql name=&quot;code&quot;&gt;SELECT id, name, address, city, state_province, country, website
FROM books_publisher;&lt;/PRE&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#ffffff&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;100%&quot;&gt;알림&lt;br /&gt;
&lt;br /&gt;django는 모든 field를 명시적으로 list할 때 SELECT * 를 사용하지 않는다. 이는 설계에 의해서 이다. 특정 상황에서 SELECT * 는 느리고 더 중요한건 python의 &quot;명시적인것이 암묵적인것 보다 좋다(Explicit is better than implicit.)&quot;라는 교리(tenent of the zen of python)를 보다 더 따르기 위해서 이다.&lt;br /&gt;
&lt;br /&gt;python의 선(zen)은 import this를 입력해 보기 바란다.&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;Publisher.objects.all()에 대해 살펴보면 다음과 같다.&lt;br /&gt;

&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;처음으로&amp;nbsp;우리가 Publisher로 정의한 model을 사용한다. 여기서 놀랄것은 없다. data를 찾기 원한다면, 해당 data를 위해 model을 사용하면 된다.&lt;/LI&gt;
&lt;LI&gt;다음으로 objects 속성을 사용한다. 이를 &lt;EM&gt;관리자(manager)&lt;/EM&gt;라고 불려진다. 관리자는 추후 chapter 10에서 다뤄질 예정이다. 여기에서는, 당신이 알기 원하는것은, 관리자가 중요한것을 포함하는 data에 모든 &quot;table-level&quot; 동작을 처리하는가, 일것이다.&lt;br /&gt;
&lt;br /&gt;모든 model은 자동으로 objects 관리자를 가지고 있다. model instance를 찾기 원할 때 마다 언제든 사용할 수 있다.&lt;/LI&gt;
&lt;LI&gt;마지막으로 all()이다. 이는 objects 관리자에서 database의 모든 row를 전달해라는 method이다. 비록 이것이 list 처럼 &lt;EM&gt;보일&lt;/EM&gt;지라도 실제로는 &lt;EM&gt;QuerySet&lt;/EM&gt;이다. 이는 database로 부터 row의 특정 집합을 표현한 object이다. 이 chapter의 나머지에서 list처럼 다루는 방법을 볼 것이다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;어떠한 database 검색도 이러한 패턴을 가진다. query를 위해 model에 첨부된 manager의 mehtod를 호출한다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;&lt;FONT color=#2b8400&gt;data 필터링하기&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;database로 부터 &lt;EM&gt;모든&lt;/EM&gt;것을 선택(select)하는 경우는 매우 드문 일이다. 대부분 data의 일부를 다루길 원할 것이다. django에서 filter() method를 이용하여 data를 필터할 수 있다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;filter&lt;/STRONG&gt;&lt;/FONT&gt;(name='Apress')&lt;br /&gt;
[&amp;lt;Publisher: Apress&amp;gt;]&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;filter()는 SQL의 WHERE clause에 해당된다. 위의 예는 아래와 같이 번역될 수 있다.&lt;br /&gt;
&lt;PRE class=sql name=&quot;code&quot;&gt;SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name = 'Apress';&lt;/PRE&gt;다음과 같이 여러개의 argument를 전달할 수 있다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;filter&lt;/STRONG&gt;&lt;/FONT&gt;(country=&quot;U.S.A.&quot;, state_province=&quot;CA&quot;)&lt;br /&gt;
[&amp;lt;Publisher: Apress&amp;gt;]&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;filter()에 전달된&amp;nbsp;여러개의 argument는 SQL의 AND clause로 번역된다. 이는 다음과 같다.&lt;br /&gt;
&lt;PRE class=sql name=&quot;code&quot;&gt;SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE country = 'U.S.A.'
AND state_province = 'CA';&lt;/PRE&gt;기본 검색은 SQL의 = 연산자이다. 다른 검색(lookup) type은 다음과 같다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;filter&lt;/STRONG&gt;&lt;/FONT&gt;(name__contains=&quot;press&quot;)&lt;br /&gt;
[&amp;lt;Publisher: Apress&amp;gt;]&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;name과 contains 사이에 &lt;EM&gt;이중&lt;/EM&gt; '_' 문자가 사용되고 있다. python 처럼 django에서도 이중 '_' 문자는 몇몇 &quot;마법&quot;과도 같은 기능을 수행하는데, __contains는 SQL의 LIKE statement로 동작된다.&lt;br /&gt;
&lt;PRE class=sql name=&quot;code&quot;&gt;SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name LIKE '%press%';&lt;/PRE&gt;많은 형태의&amp;nbsp;lookup type이 가능하며, icontains(대소문자 구별 없는 LIKE), startswith와 endswith, 그리고 range(SQ의 BETWEEN)등이 있다. 부록 C에 관련 사항들이 정리되어 있다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#2b8400&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;단일 object 구하기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;br /&gt;
&lt;/STRONG&gt;&lt;br /&gt;
filter() 예제는 list처럼 사용할 수 있는 QuerySet을 전달받아 사용한다. 만약 list와 반대로 object 한개만 가져올 수 있다면 편리할 때가 있다. 이는 get() method를 이용한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;get&lt;/STRONG&gt;&lt;/FONT&gt;(name=&quot;Apress&quot;)&lt;br /&gt;
&amp;lt;Publisher: Apress&amp;gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;list(QuerySet)대신 안일 object가 전달된다. 그로인해 query 결과가 여러개의 object인 경우 다음과 같은 예외가 발생하게 된다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;get&lt;/STRONG&gt;&lt;/FONT&gt;(country=&quot;U.S.A.&quot;)&lt;br /&gt;
Traceback (most recent call last):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; ...&lt;br /&gt;
MultipleObjectsReturned: get() returned more than one Publisher --&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; it returned 2! Lookup parameters were {'country': 'U.S.A.'}&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;역시 비슷하게 결과가 없는 경우에도 예외가 발생한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;get&lt;/STRONG&gt;&lt;/FONT&gt;(name=&quot;Penguin&quot;)&lt;br /&gt;
Traceback (most recent call last):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; ...&lt;br /&gt;
DoesNotExist: Publisher matching query does not exist.&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;DoesNotExist 예외는 model class의 속성(Publisher.DoesNotExist)이다. application에서 이러한 예외를 잡기 위해서는 다음과 같이 수행하라.&lt;br /&gt;
&lt;PRE class=python name=&quot;code&quot;&gt;try:
	p = Publisher.objects.get(name='Apress')
except Publisher.DoesNotExist:
	print &quot;Apress isn't in the database yet.&quot;
else:
	print &quot;Apress is in the database.&quot;&lt;/PRE&gt;&lt;FONT color=#2b8400&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;data 정렬(ordering)하기&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;br /&gt;
&lt;br /&gt;여태까지의 예제를 보면, 꼭 random 순서로 object를 전달 받은 것처럼 보였을 것이다. 어떤것을 상상하지는 말라. database가 어떤 순서로 결과를 보고하는지에 대해 아직 얘기하지 않아서, database에 의해 선택된 몇몇 전용 순서로 봤을 뿐이다.&lt;br /&gt;
&lt;br /&gt;django application에서 특정 값에 따라 결과 순서를 정렬하고 싶을 때가 있다(예를 들어, 알파벳 순서). 이를 위해 order_by() method를 사용한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;order_by&lt;/STRONG&gt;&lt;/FONT&gt;(&quot;name&quot;)&lt;br /&gt;
[&amp;lt;Publisher: Apress&amp;gt;, &amp;lt;Publisher: O'Reilly&amp;gt;]&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;이는 이전의 all() 예제와 크게 다를거 없어 보이는데, SQL은 다음과 같이 실행된다.&lt;br /&gt;
&lt;br /&gt;
&lt;P&gt;&lt;/P&gt;&lt;PRE class=sql name=&quot;code&quot;&gt;SELECT id, name, address, city, state_province, country, website
FROM books_publisher
ORDER BY name;&lt;/PRE&gt;당신이 원하는 어떤 field도 순서를 정할 수 있다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;order_by&lt;/STRONG&gt;&lt;/FONT&gt;(&quot;address&quot;)&lt;br /&gt;
[&amp;lt;Publisher: O'Reilly&amp;gt;, &amp;lt;Publisher: Apress&amp;gt;]&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;order_by&lt;/STRONG&gt;&lt;/FONT&gt;(&quot;state_province&quot;)&lt;br /&gt;
[&amp;lt;Publisher: Apress&amp;gt;, &amp;lt;Publisher: O'Reilly&amp;gt;]&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;다수의 field에 대한 정렬을 정하기 위해서는, 아래와 같이 여러개의 argument를 사용하면 된다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;order_by&lt;/STRONG&gt;&lt;/FONT&gt;(&quot;state_province&quot;, &quot;address&quot;)&lt;br /&gt;
&amp;nbsp;[&amp;lt;Publisher: Apress&amp;gt;, &amp;lt;Publisher: O'Reilly&amp;gt;]&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;역방향으로&amp;nbsp;정렬하려면 '-' 문자를 사용한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;order_by&lt;/STRONG&gt;&lt;/FONT&gt;(&quot;-name&quot;)&lt;br /&gt;
[&amp;lt;Publisher: O'Reilly&amp;gt;, &amp;lt;Publisher: Apress&amp;gt;]&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;order_by()를 사용하여 유연성을 가질 수 있지만, 꽤나 반복적인 일일 수 있다. 대부분&amp;nbsp;정렬할때 특정한 한개의 field를 사용한다. 이러한 경우 djangos는 model의 기본 순서를 정하도록 도움을 준다.&lt;br /&gt;
&lt;PRE class=python name=&quot;code&quot;&gt;class Publisher(models.Model):
	name = models.CharField(max_length=30)
	address = models.CharField(max_length=50)
	city = models.CharField(max_length=60)
	state_province = models.CharField(max_length=30)
	country = models.CharField(max_length=50)
	website = models.URLField()
	
	def __unicode__(self):
		return self.name

	class Meta:
		ordering = ['name']&lt;/PRE&gt;이제 새로운 개념인 class Meta: 를 소개한다. 이는 Publisher class 정의(class Publisher의 편집 Tab) 내부에 포함되어 있다. 다양한 model에서 지정할 수 있는 옵션을 결정하기 위해 사용된다. Meta의 모든 참조는 부록 B에서 구할 수 있으며, 여기에서는 ordering 옵션만 다루도록 한다. 만약 이 값을 지정한다면, django로 하여금 order_by()가 지정되지 않았을 때 모든 Publisher objects는 name field에 의해&amp;nbsp;정렬되도록 알려준다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#2b8400&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;검색(lookup) 연쇄처리&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;data를 필터하는 방법을 알아봤는데, 이제 그것을 정렬해 보도록 한다. 이는 검색과 함께 &quot;연결&quot;하면 된다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;filter&lt;/STRONG&gt;&lt;/FONT&gt;(country=&quot;U.S.A.&quot;)&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;.order_by&lt;/STRONG&gt;&lt;/FONT&gt;(&quot;-name&quot;)&lt;br /&gt;
[&amp;lt;Publisher: O'Reilly&amp;gt;, &amp;lt;Publisher: Apress&amp;gt;]&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;이는 아래와 같다.&lt;br /&gt;
&lt;PRE class=python name=&quot;code&quot;&gt;SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE country = 'U.S.A'
ORDER BY name DESC;&lt;/PRE&gt;&lt;STRONG&gt;&lt;FONT color=#2b8400&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;data 자르기(slicing)&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;또다른 통상적인 요구사항은 고정된 크기의 row를 검색하는 일이다. database에 수천개의 publisher가 있는데, 첫번째 하나만 구하기를 원할 떄이다. 이는 python의 표준 list 자르기 문법을 사용하면 된다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;order_by&lt;/STRONG&gt;&lt;/FONT&gt;('name')&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;[0]&lt;/STRONG&gt;&lt;/FONT&gt;&lt;br /&gt;
&amp;lt;Publisher: Apress&amp;gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;이는 아래와 같이 번역된다.&lt;br /&gt;
&lt;PRE class=sql name=&quot;code&quot;&gt;SELECT id, name, address, city, state_province, country, website
FROM books_publisher
ORDER BY name
LIMIT 1;&lt;/PRE&gt;유사하게 다음과 같이 범위 지정이 가능하다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;order_by&lt;/STRONG&gt;&lt;/FONT&gt;('name')&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;[0:2]&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;이는 2개의 object를 전달하는데, 다음과 같이 번역된다.&lt;br /&gt;
&lt;PRE class=sql name=&quot;code&quot;&gt;SELECT id, name, address, city, state_province, country, website
FROM books_publisher
ORDER BY name
OFFSET 0 LIMIT 2;&lt;/PRE&gt;음수값으로 자르기는 지원되지 &lt;EM&gt;않는다&lt;/EM&gt;.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;order_by&lt;/STRONG&gt;&lt;/FONT&gt;('name')&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;[-1]&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
Traceback (most recent call last):&lt;br /&gt;
&amp;nbsp; ...&lt;br /&gt;
AssertionError: Negative indexing is not supported.&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;이것은 다음과 같이 수정하여 사용하면 된다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;order_by&lt;/STRONG&gt;&lt;/FONT&gt;('-name')&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;[0]&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;
&lt;STRONG&gt;&lt;FONT color=#2b8400&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;단일 statement로 여러개의 object를 업데이트하기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;&quot;data 삽입과 업데이트&quot; 부분에서 봤듯이 save() method로 row의 모든 column을 업데이트할 수 있다. application에 따라 column의 부분집합만 update하기를 원할 수 있다.&lt;br /&gt;
&lt;br /&gt;예를 들어, Apress Publisher를 'Apress'에서 'Apress Publishing'으로 업데이트하고자 한다면, 아래와 같이 save()를 이용한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; p = Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;get&lt;/STRONG&gt;&lt;/FONT&gt;(name='Apress')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; p.name = 'Apress Publishing'&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; p.save()&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;이는 대략 다음과 같이 SQL로 번역가능하다.&lt;br /&gt;
&lt;PRE class=sql name=&quot;code&quot;&gt;SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name = 'Apress';

UPDATE books_publisher SET
    name = 'Apress Publishing',
    address = '2855 Telegraph Ave.',
    city = 'Berkeley',
    state_province = 'CA',
    country = 'U.S.A.',
    website = 'http://www.apress.com'
WHERE id = 52;&lt;/PRE&gt;(publisher id가 52인 경우로 가정함)&lt;br /&gt;
&lt;br /&gt;이 예를 통해 django의 save() method는 cloumn의 모든 것을 세팅하는데, name column만 하는 것이 아니다. 만약&amp;nbsp;다른 column이 다른 process에서 변경이 가능한 환경이라면, 변경하고자 하는 column&lt;EM&gt;만&lt;/EM&gt; 변경하는것이 보다 올바르다. 이를 위해 QuerySet object의 update() method를 사용한다. 다음은 그 예이다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;filter&lt;/STRONG&gt;&lt;/FONT&gt;(id=52).&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;update&lt;/FONT&gt;&lt;/STRONG&gt;(name='Apress Publishing')&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;SQL 번역은 race condition이 발생하지 않도록 보다 효과적으로 대응된다.&lt;br /&gt;
&lt;PRE class=sql name=&quot;code&quot;&gt;UPDATE books_publisher
SET name = 'Apress Publishing'
WHERE id = 52;&lt;/PRE&gt;update() method는 어떤 QuerySet에서도 동작하며, 이는 규모가 있는 여러개의 record를 편집가능하다는 뜻이다. 아래는 'U.S.A'로 된 country를 'USA'로 변경하는 예제이다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;filter&lt;/STRONG&gt;&lt;/FONT&gt;(country=&quot;U.S.A&quot;).&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;update&lt;/FONT&gt;&lt;/STRONG&gt;(country=&quot;USA&quot;)&lt;br /&gt;
2&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;update() method는 리턴값을 전달하는데, 이는 수정된 record의 개수를 의미한다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;object 삭제하기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;database로 부터 object를 삭제하기 위해, object의 delete() method를 호출한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; p = Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;get&lt;/STRONG&gt;&lt;/FONT&gt;(name=&quot;O'Reilly&quot;)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; p.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;delete&lt;/FONT&gt;&lt;/STRONG&gt;()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;all&lt;/STRONG&gt;&lt;/FONT&gt;()&lt;br /&gt;
[&amp;lt;Publisher: Apress Publishing&amp;gt;]&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;delete()은 QuerySet의 결과로 호출할 수 있다. 이는 update() method와 비슷한데, 아래를 참조하라.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;filter&lt;/STRONG&gt;&lt;/FONT&gt;(country='USA').delete()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;all&lt;/STRONG&gt;&lt;/FONT&gt;().&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;delete&lt;/FONT&gt;&lt;/STRONG&gt;()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;all&lt;/STRONG&gt;&lt;/FONT&gt;()&lt;br /&gt;
[]&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;data를 delete할때 주의하기 바란다. 특정 table에 있는 임의의 data를 모두 삭제하는 것을 방지하기 위해, table의 &lt;EM&gt;모든&lt;/EM&gt; data를 삭제하기 원한다면 django는 all()을 명시적으로 사용할 것을 요구한다. 아래는 제대로 동작하지 않는다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;delete&lt;/STRONG&gt;&lt;/FONT&gt;()&lt;br /&gt;
Traceback (most recent call last):&lt;br /&gt;
&amp;nbsp; File &quot;&amp;lt;console&amp;gt;&quot;, line 1, in &amp;lt;module&amp;gt;&lt;br /&gt;
AttributeError: 'Manager' object has no attribute 'delete'&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;all() method를 추가하면 가능하다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;all&lt;/STRONG&gt;&lt;/FONT&gt;().&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;delete&lt;/FONT&gt;&lt;/STRONG&gt;()&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;만약 data의 일부만 삭제하고자 한다면, all()를 사용하지 말아야 한다. 다음은 그 예이다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; Publisher.&lt;FONT color=#ff8b16&gt;objects.&lt;STRONG&gt;filter&lt;/STRONG&gt;&lt;/FONT&gt;(country='USA').&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;delete&lt;/FONT&gt;&lt;/STRONG&gt;()&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;br /&gt;&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-125-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-125-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=28536778&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/125&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/django&quot;&gt;django&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/django/the%20django%20book%20study&quot;&gt;the django book study&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/126&quot; &gt;[06] django admin site&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(2)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/27&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/125&quot; &gt;[05] django의 model&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(1)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/124&quot; &gt;[04] django의 template&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(2)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/123&quot; &gt;[03] django 1.4의 view와 urlconfs&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/04&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/122&quot; &gt;[02] django 1.4 설치와 project 생성하기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/120&quot; &gt;[01] django 소개&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/28&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>the django book study</category>
			<category>django</category>
			<category>django 1.4</category>
			<category>model</category>
			<category>MVC</category>
			<category>SQL</category>
			<category>SQLite</category>
			<category>Unicode</category>
			<category>unicode object</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/125</guid>
			<comments>http://greenfishblog.tistory.com/125#entry125comment</comments>
			<pubDate>Thu, 12 Apr 2012 08:21:24 +0900</pubDate>
		</item>
		<item>
			<title>[04] django의 template</title>
			<link>http://greenfishblog.tistory.com/124</link>
			<description>&lt;DIV&gt;본글은 &lt;A href=&quot;http://www.djangobook.com/en/2.0/chapter04/&quot;&gt;http://www.djangobook.com/en/2.0/chapter04/&lt;/A&gt;&amp;nbsp;에서 참조되었습니다.&lt;br /&gt;
&lt;br /&gt;이전장에서의 view를 통해 text를 리턴하는 것을 이상하게 생각할 수 있을 것이다. 다시말해 HTML은 아래와 같이 python code에 hard-code되어 있다.&lt;/DIV&gt;&lt;TEXTAREA style=&quot;WIDTH: 390px; HEIGHT: 104px&quot; class=python rows=3 cols=38 name=code&gt;def current_datetime(request):
    now = datetime.datetime.now()
    html = &quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;It is now %s.&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&quot; % now
    return HttpResponse(html)&lt;/TEXTAREA&gt;&lt;br /&gt;
비록 이 기술이 view의 작동을 설명하는데 목적을 뒀지만, 이와 같이 hard-code된 HTML을 view에서 사용하는 것은 좋지 않은 생각이다.&lt;br /&gt;

&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;page design의 변경이 python code의 변경을 요구한다. site의 design은 python code보다 훨씬 자주 변경되는데, 그래서 design이 python code 수정없이 design을 변경하는 방법이 필요하다.&lt;/LI&gt;
&lt;LI&gt;python code를 작성하고 HTML을 design하는데는 두개의 다른 원리가 있는데, 대부분의 web 개발 도구는 개별 사람(혹은 부서)의 책임을 분리한다. designer와 HTML/CSS 개발자는 python code를 작성할 필요가 없다.&lt;/LI&gt;
&lt;LI&gt;만일 개발자가 python을 개발할 수 있고, 동시에 designer는 template 작업을 할 수 있다면, 최고의 효과를 발휘할 것이다. 한작업 끝나고 다른 작업이 끝날때 까지 기다리는 것보다 효과적이다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;이러한 이유로 python code 그자체로 부터 page를 직업 design하지 않도록 분리하는 것이 보다 깔끔하고 유지보수에 유용하다고 본다. 이제 이러한 django의 &lt;EM&gt;template system&lt;/EM&gt;을 설명할 것이다.&lt;br /&gt;
&lt;br /&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;template system 기초&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;br /&gt;
&lt;br /&gt;django의 template는 document의 표현을 분리하는데 사용되는 text 문자열이다. template는 placeholder(위치)와 문서를 어떻게 표시하는지를&amp;nbsp;조절하는 기본 logic(template tags)의 다양한 bit를 정의한다. 보통 template는 HTML을 생산하는데 사용되는데, django template는&amp;nbsp;어떤 text 기반의 format을 만들어 내는 능력이 있다.&lt;br /&gt;
&lt;br /&gt;이제 간단한 template 예제를 살펴보자. 이러한 django template는 임의의 한 회사의 상품을 주문하는데 감사하다는 내용의 HTML page로 구성되어 있다.&lt;TEXTAREA style=&quot;WIDTH: 432px; HEIGHT: 566px&quot; class=html rows=21 cols=43 name=code&gt;&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;Ordering notice&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;

&amp;lt;h1&amp;gt;Ordering notice&amp;lt;/h1&amp;gt;

&amp;lt;p&amp;gt;Dear {{ person_name }},&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Thanks for placing an order from {{ company }}. It's scheduled to
ship on {{ ship_date|date:&quot;F j, Y&quot; }}.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Here are the items you've ordered:&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
{% for item in item_list %}
    &amp;lt;li&amp;gt;{{ item }}&amp;lt;/li&amp;gt;
{% endfor %}
&amp;lt;/ul&amp;gt;

{% if ordered_warranty %}
    &amp;lt;p&amp;gt;Your warranty information will be included in the packaging.&amp;lt;/p&amp;gt;
{% else %}
    &amp;lt;p&amp;gt;You didn't order a warranty, so you're on your own when
    the products inevitably stop working.&amp;lt;/p&amp;gt;
{% endif %}

&amp;lt;p&amp;gt;Sincerely,&amp;lt;br /&amp;gt;{{ company }}&amp;lt;/p&amp;gt;

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/TEXTAREA&gt;&lt;br /&gt;
이러한 template는 몇몇 변수와 template tag가 포함된 기본적인 HTML이다. 자세히 살펴보면,&lt;br /&gt;
&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;괄호쌍에 의해 둘러쌓인 text(예, {{ person_name }})은 변수이다. 이는, &quot;주어진 이름을 가진 변수의 값을 넣어라&quot;라는 뜻이다. (어떻게 변수의 값을 구할 것인가? 그건 그 당시의 값으로 결정된다.)&lt;/LI&gt;
&lt;LI&gt;% 문자에 의해 쌓인 text(예, {% if ordered_warranty %})는 &lt;EM&gt;template tag&lt;/EM&gt;이다. 이것의 정의는 조금 광대한데, tag는 template system에 &quot;뭔가 하라&quot;라고 알려준다.&lt;br /&gt;
&lt;br /&gt;위 예에서는&amp;nbsp;for tag({% for item in item_list %})과 if tag({% if orderred_warrenty %})가 사용되었다.&lt;br /&gt;
&lt;br /&gt;for tag는 python의 for 구문과 유사하게 동작하는데, 각각의 item이 순서대로 loop를 돌수 있도록 한다. if tag는 예상했듯이 &quot;if&quot; 구문과 논리적으로 유사하게 동작한다. 특별한 경우 tag는 ordered_warranty 변수의 값에 따라 True로 결정한다. 그런 경우 {% if ordered_warranty %}와 {% else %} 사이가 표시된다. 그렇지 않은 경우, {% else %}와 {% endif %} 사이가 표시된다. {% else %}는 옵션 사항이다.&lt;/LI&gt;
&lt;LI&gt;마지막으로, template의 두번째 문단은 &lt;EM&gt;filter&lt;/EM&gt;의 예를 보여주는데, 변수를 formatting을 변경하는 가장 편한 방법을 제공한다. {{ ship_date|date:&quot;F j, Y&quot; }}는 ship_date 변수를 date filter로 전달하는 것이며, filter의 argument로 &quot;F j, Y&quot;가 전달된다. date filter는 해당 argument에 의해 지정되어 특별하게 처리되게 주어진 format으로 date를 format한다. filter는 pipe 문자(|)를 사용한다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;각 django template는 몇개의 built-in tag와 filter가 있다. 대부분 본 section에서 다루게 될 것이다. &lt;br /&gt;
그리고, 자신만의 고유한 filter와 tag를 만들 수 있는데, 이는 chapter 9에서 다룰 것이다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;template system 사용하기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;django의 template sytem이 어떻게 동작하는지를 확인할 차례이다. 이전 chapter에서 만들어진 view를 아직 통합하지 않았다. 일단 해당 sytem이 django에 의존하여 동작하는지를 알아내는 것을 목표로 한다. (다르게 말하면, 보통 django view내의 template system을 사용할 것인데, 그러나 django view가 아닌 어느곳에서든 사용가능한 python library인지를 확인하기를 원할 것이다.)&lt;br /&gt;
&lt;br /&gt;python code로 구성된 django template system을 사용할 수 있는 가장 기본적인 방법은 아래와 같다.&lt;/P&gt;
&lt;OL style=&quot;LIST-STYLE-TYPE: decimal&quot;&gt;
&lt;LI&gt;raw template code를 제공하는 것에 의해&amp;nbsp;Template object를 생성한다.&lt;/LI&gt;
&lt;LI&gt;변수(&lt;EM&gt;context&lt;/EM&gt;)들의 집합과 함께 Template object의 render() method를 호출한다. 그러면 context로 부터 계산된 모든 변수와 template tag를 가지고 fuuly renderred template를 문자열로 구한다.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;코드상으로, 이것은 다음과 같이 나타난다.&lt;br /&gt;
&lt;/P&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;C:\mydjango\mysite&amp;gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;/STRONG&gt; manage.py &lt;STRONG&gt;shell&lt;/STRONG&gt;&lt;/FONT&gt;&lt;br /&gt;
Python 2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel)] on&lt;br /&gt;
win32&lt;br /&gt;
Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.&lt;br /&gt;
(InteractiveConsole)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;from &lt;STRONG&gt;django&lt;/STRONG&gt; import &lt;STRONG&gt;template&lt;/STRONG&gt;&lt;/FONT&gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t = &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;template.Template&lt;/STRONG&gt;&lt;/FONT&gt;('My name is {{ name }}.')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; c = &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;template.Context&lt;/FONT&gt;&lt;/STRONG&gt;({'name': 'Adrian'})&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;print&lt;/STRONG&gt; t.&lt;STRONG&gt;render&lt;/STRONG&gt;&lt;/FONT&gt;(c)&lt;br /&gt;
My name is Adrian.&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; c = &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;template.Context&lt;/FONT&gt;&lt;/STRONG&gt;({'name': 'Fred'})&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;print&lt;/STRONG&gt; t.&lt;STRONG&gt;render&lt;/STRONG&gt;&lt;/FONT&gt;(c)&lt;br /&gt;
My name is Fred.&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;자세한&amp;nbsp; 설명은 다음 section에서 다루도록 한다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;&lt;FONT color=#2b8400&gt;Template object 생성하기&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;Template object를 생성하는데 가장 쉬운 방법은 직접 초기화하는 것이다. Template class는 django.template module에 있고 생성자는 하나의 argument를 받는데, 이는 raw template code이다. python interactive interpreter가 어떻게 code를 동작시키는지 확인해 보자.&lt;br /&gt;
&lt;br /&gt;mysite project directory(django-admin.py startproject)에서 python manage.py shell을 통해 interactive interpreter를 시작한다. (그래야만 DJANGO_SETTING_MODULE를 받아들여 오류없이 동자하게 된다.)&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;from django.template import Template&lt;/FONT&gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t = &lt;FONT color=#ff8b16&gt;Template&lt;/FONT&gt;('My name is {{ name }}.')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;print &lt;/FONT&gt;t&lt;br /&gt;
&amp;lt;django.template.base.Template object at 0x011E2BD0&amp;gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;0x011E2BD0은 매번 다르게 나타나는데 별 상관없다.&lt;br /&gt;
&lt;br /&gt;Template object를 생성하면 template system은 rendering 준비를 위해 최적화된 형태로 내부로 raw template code를 compile한다. 그러나 template code에 syntax error가 있다면 Tempate() 호출시 TemplateSyntaxError execption이 발생한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;from django.template import Template&lt;/FONT&gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t = &lt;FONT color=#ff8b16&gt;Template&lt;/FONT&gt;('{% notatag %}')&lt;br /&gt;
Traceback (most recent call last):&lt;br /&gt;
&amp;nbsp; File &quot;&amp;lt;console&amp;gt;&quot;, line 1, in &amp;lt;module&amp;gt;&lt;br /&gt;
&amp;nbsp; File &quot;C:\Python25\Lib\site-packages\django\template\base.py&quot;, line 125, in __i&lt;br /&gt;
nit__&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; self.nodelist = compile_string(template_string, origin)&lt;br /&gt;
&amp;nbsp; File &quot;C:\Python25\Lib\site-packages\django\template\base.py&quot;, line 153, in com&lt;br /&gt;
...&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; raise self.error(token, &quot;Invalid block tag: '%s'&quot; % command)&lt;br /&gt;
TemplateSyntaxError: Invalid block tag: 'notatag'&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;에러 메시지의 마지막에 &quot;block tag&quot;는 {% notatag %}를 가리킨다. &quot;Block tag&quot;와 &quot;template tag&quot;는 동의어이다.&lt;br /&gt;
&lt;br /&gt;시스템은 다음 경우일때 TemplateSyntaxError exception을 발생한다.
&lt;P&gt;&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;무효한(invalid) tag&lt;/LI&gt;
&lt;LI&gt;무효한 argument를 유효한(valid) tag에 전달할 때&lt;/LI&gt;
&lt;LI&gt;무효한 filter&lt;/LI&gt;
&lt;LI&gt;무효한 argument를 유효한 filter에 전달할 때&lt;/LI&gt;
&lt;LI&gt;무효한 template syntax&lt;/LI&gt;
&lt;LI&gt;닫지 않은 tag (for tag는 closing tag를 요구한다)&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#2b8400&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;Template rendering 하기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;Template object를 일단 생성하였다면, &lt;EM&gt;context&lt;/EM&gt;를 제공하여 data를 전달할 수 있다.&amp;nbsp;context는 변수명과 그것와 연계된 값을 가지는 단순한 집합이다.&lt;br /&gt;
&lt;br /&gt;context는 django.template module에 있는&amp;nbsp;Context class에 의해&amp;nbsp;표현된다. 그것의 생성자는 옵션으로 처리된 arugment가 하나 있는데, 그것은 변수명을 값으로 매핑하는데 사용될 사전(dictionary)이다. Template object의 render() method를 template를 채울 context와 함께 호출한다.&lt;br /&gt;
&lt;/P&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;from django.template import Context, Template&lt;/FONT&gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t = &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;Template&lt;/STRONG&gt;&lt;/FONT&gt;('My name is {{ name }}.')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; c = &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;Context&lt;/STRONG&gt;&lt;/FONT&gt;({'name':'Stephane'})&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;render&lt;/FONT&gt;&lt;/STRONG&gt;(c)&lt;br /&gt;
u'My name is Stephane.'&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;t.render(c)는 Unicode object라는 것을 이곳에서 확인할 수 있는데, 이는 문자열 앞의 u를 통해 알 수 있다. django는 framework 도처에 있는 일반 문자열을 대신해 Unicode object를 사용한다. 만일 그것의 영향을 이해했다면, 무대 뒤에서 django가 수행해 주는 정제된 작업들에 대해 고마워할 것이다. 그것의 영향을 이해하지 못했다면, 걱정하지 마라. django의 unicode 지원이 &quot;A-Z&quot;까지의 영어를 넘어서는 다양한 wide character를 지원하기 위한 고통을 줄여주는 것을 알게 될 것이기 때문이다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#eaf4cf&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;100%&quot;&gt;사전(Dictionary)과 Context&lt;br /&gt;
&lt;br /&gt;python diectionary는 알려진 key와 변수값이 매핑되어 있는 것을 말한다. Context는 dictionary와 비슷한데, Context는 추가 기능을 제공한다. (chapter 9)&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;변수명은 알파벳(A-Z, a-z)로 시작해야 하고, 숫자, _, 그리고 . 을 포함할 수 있다. (.은 특별한 의미를 가진다). 변수명은 대소문자를 구별한다.&lt;br /&gt;
&lt;br /&gt;아래는 그 예제이다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;from django.template import Template, Context&lt;/FONT&gt;&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;&amp;gt;&amp;gt;&amp;gt; raw_template = &quot;&quot;&quot;&amp;lt;p&amp;gt;Dear {{ person_name }},&amp;lt;/p&amp;gt;&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;...&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;... &amp;lt;p&amp;gt;Thanks for placing an order from {{ company }}. It's scheduled to&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;... ship on {{ ship_date|date:&quot;F j, Y&quot; }}.&amp;lt;/p&amp;gt;&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;...&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;... {% if ordered_warranty %}&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;... &amp;lt;p&amp;gt;Your warranty information will be included in the packaging.&amp;lt;/p&amp;gt;&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;... {% else %}&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;... &amp;lt;p&amp;gt;You didn't order a warranty, so you're on your own when&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;... the products inevitably stop working.&amp;lt;/p&amp;gt;&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;... {% endif %}&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;...&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;... &amp;lt;p&amp;gt;Sincerely,&amp;lt;br /&amp;gt;{{ company }}&amp;lt;/p&amp;gt;&quot;&quot;&quot;&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;&amp;gt;&amp;gt;&amp;gt; t = &lt;FONT color=#ff8b16&gt;Template&lt;/FONT&gt;(raw_template)&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;import datetime&lt;/FONT&gt;&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;&amp;gt;&amp;gt;&amp;gt; c = &lt;FONT color=#ff8b16&gt;Context&lt;/FONT&gt;({'person_name': 'John Smith',&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 'company': 'Outdoor Equipment',&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 'ship_date': datetime.date(2009, 4, 2),&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 'ordered_warranty': False})&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;&amp;gt;&amp;gt;&amp;gt; t.&lt;FONT color=#ff8b16&gt;render&lt;/FONT&gt;(c)&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;u&quot;&amp;lt;p&amp;gt;Dear John Smith,&amp;lt;/p&amp;gt;\n\n&amp;lt;p&amp;gt;Thanks for placing an order from Outdoor Equipme&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;nt. It's scheduled to\nship on April 2, 2009.&amp;lt;/p&amp;gt;\n\n\n&amp;lt;p&amp;gt;You didn't order a war&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;ranty, so you're on your own when\nthe products inevitably stop working.&amp;lt;/p&amp;gt;\n\n&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;\n&amp;lt;p&amp;gt;Sincerely,&amp;lt;br /&amp;gt;Outdoor Equipment&amp;lt;/p&amp;gt;&quot;&lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;각 과정의 의미를 살펴보자.
&lt;P&gt;&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;처음으로, django.template에 있는 Template와 Context class를 import하였다.&lt;/LI&gt;
&lt;LI&gt;raw_template 변수로 template의 raw text를 넣는다. 참고로 3개의 따옴표(&quot;&quot;&quot;)로 표기하였는데, 이는 여러개의 라인을 받기 위함이다. 대조적으로 단일 따옴표는 여러개의 라인을 받지 못한다.&lt;/LI&gt;
&lt;LI&gt;다음으로 t라는 template object를 생성하는데, raw_template를 Template class의 생성자에 전달한다.&lt;/LI&gt;
&lt;LI&gt;python의 datetime module를 import하는데, 다음 구문에 사용하기 때문이다.&lt;/LI&gt;
&lt;LI&gt;c라는 Context object를 생성한다. Context 생성자에 python dictionary를 전달하고, 그것은 변수명과 값으로 매핑되어 있다.&lt;/LI&gt;
&lt;LI&gt;마지막으로 context를 가지고 render()를 호출한다. 이는 rendered template가 리턴된다. template 변수가 실제값으로 변경되고, template tag를 실행한다.&lt;br /&gt;
&lt;br /&gt;&quot;You didn't order a warranty&quot; 문단은 orderred_warranty 변수가 False인 경우 표기된다. 역시 April 2, 2009와 같이 date가 표기되는데, 'F j, Y' 형태의 format으로 적용된다.&lt;br /&gt;
&lt;br /&gt;python의 초보자라면 output에 새로운 개행 대신 왜 &lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;\n&lt;/SPAN&gt;이 포함되었는지 의아해 할 것이다. python interactive interpreter의 미묘함 때문인데, t.render(c)는 문자열을 리턴하는데 interactive interpreter는 기본적으로&amp;nbsp;그 문자열의 값을 출력하기 보다는, 그 문자열의 &lt;EM&gt;표현(representation)&lt;/EM&gt;을 출력한다. 만일 &lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;\n &lt;/SPAN&gt;대신 실제 개행이 되는 것으로 출력하길 원한다면, print t.render(c)와 같이 print 구문을 이용한다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;이것이 django template system의 기초를 알아보았는데, template 문자열을 작성하고 Template object를 생성하며, Context를 생성하고 그리고 render()를 호출하는 것으로 구성된다.&lt;br /&gt;
&lt;br /&gt;&lt;FONT color=#2b8400&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;여러개의 Context에 동일한 Template&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;br /&gt;
&lt;br /&gt;일단 Template object를 만들었다면, 다음과 같이 여러개의 context를 render할 수 있다.&lt;br /&gt;
&lt;/P&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;from django.template import Template, Context&lt;/FONT&gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t = &lt;FONT color=#ff8b16&gt;Template&lt;/FONT&gt;('Hello, {{ name }}')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;print &lt;/FONT&gt;t.&lt;FONT color=#ff8b16&gt;render&lt;/FONT&gt;(&lt;FONT color=#ff8b16&gt;Context&lt;/FONT&gt;({'name':'John'}))&lt;br /&gt;
Hello, John&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;print &lt;/FONT&gt;t.&lt;FONT color=#ff8b16&gt;render&lt;/FONT&gt;(&lt;FONT color=#ff8b16&gt;Context&lt;/FONT&gt;({'name':'Julie'}))&lt;br /&gt;
Hello, Julie&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;print &lt;/FONT&gt;t.&lt;FONT color=#ff8b16&gt;render&lt;/FONT&gt;(&lt;FONT color=#ff8b16&gt;Context&lt;/FONT&gt;({'name':'Pat'}))&lt;br /&gt;
Hello, Pat&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;이러한 방법으로 여러개의 context를 사용하는 경우, Template object는 한번만 생성하고, render()를 여러번 호출하는 것이 효과적이다.&lt;br /&gt;

&lt;P&gt;&lt;/P&gt;&lt;TEXTAREA style=&quot;WIDTH: 410px; HEIGHT: 177px&quot; class=python rows=6 cols=42 name=code&gt;# Bad
for name in ('John', 'Julie', 'Pat'):
    t = Template('Hello, {{ name }}')
    print t.render(Context({'name': name}))

# Good
t = Template('Hello, {{ name }}')
for name in ('John', 'Julie', 'Pat'):
    print t.render(Context({'name': name}))
&lt;/TEXTAREA&gt;&lt;br /&gt;
django의 template parsing은 꽤나 속도가 빠른 편이다. 대부분의 parsing은 단일 regular expression을 호출하는것을 경유한다. XML 기반의 template engine과 비교해서 극명한 대조를 이룬다. 즉, XML parser 부하의 부하를 발생시키는 것으로 django의 template render engine 보다 훨씬 느리다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#2b8400&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;Context 변수 찾기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;예제에서 우리는 context에 단순한 값만 전달했는데, 대부분 문자열이였고 datetime 한개가 더 있었다. 그러나 template system은 보다 복잡한 data structure를 처리하는데, 예를 들어, list나 dictionary 그리고 custom object등이다.&lt;br /&gt;
&lt;br /&gt;django에서는 복잡한 data strucrure의 값을 구하기 위한 traversing은 점(.)문자를 이용하는 것이다. 이러한 '.'을 사용하여 dictionary key, attribute, method, 혹은 object의 index에 접근한다.&lt;br /&gt;
&lt;br /&gt;예를 들어, python의 dictionary를 template에 전달하는 것을 가정해보라. 저런 dictionary의 값을 접근하기 위해 '.'을 사용한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;from django.template import Template, Context&lt;br /&gt;
&lt;/FONT&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;person &lt;/FONT&gt;= {'name': 'Sally', 'age': '43'}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t = &lt;FONT color=#ff8b16&gt;Template&lt;/FONT&gt;('{{ person&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;.&lt;/STRONG&gt;&lt;/FONT&gt;name }} is {{ person&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;.&lt;/FONT&gt;&lt;/STRONG&gt;age }} years old.')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; c = &lt;FONT color=#ff8b16&gt;Context&lt;/FONT&gt;({'person': person})&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t.&lt;FONT color=#ff8b16&gt;render&lt;/FONT&gt;(c)&lt;br /&gt;
u'Sally is 43 years old.'&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&lt;/FONT&gt;&amp;nbsp;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;유사하게, '.'은 역시 object의 attribute를 접그하는데도 사용된다. 예를 들어, datetime.date object는 year, month, 그리고 day attribute가 있고 이러한 attributes를 접근하는데도 '.'이 사용된다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;from django.template import Template, Context&lt;br /&gt;
&lt;/FONT&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;import datetime&lt;br /&gt;
&lt;/FONT&gt;&amp;gt;&amp;gt;&amp;gt; d = &lt;FONT color=#ff8b16&gt;datetime.date&lt;/FONT&gt;(1993, 5, 2)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; d.year&lt;br /&gt;
1993&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; d.month&lt;br /&gt;
5&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; d.day&lt;br /&gt;
2&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t = &lt;FONT color=#ff8b16&gt;Template&lt;/FONT&gt;('The month is {{ date.month }} and the year is {{ date.year }}.&lt;br /&gt;
')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; c = &lt;FONT color=#ff8b16&gt;Context&lt;/FONT&gt;({'date': d})&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t.&lt;FONT color=#ff8b16&gt;render&lt;/FONT&gt;(c)&lt;br /&gt;
u'The month is 5 and the year is 1993.'&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;그리고, '.'은 object의 method를 가리키기도 한다. 각 python 문자열은 upper()와 isdigit() 라는 method가 있고 동일한 . 문법으로 django template에 사용할 수 있다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;from django.template import Template, Context&lt;br /&gt;
&lt;/FONT&gt;&amp;gt;&amp;gt;&amp;gt; t = &lt;FONT color=#ff8b16&gt;Template&lt;/FONT&gt;('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t.&lt;FONT color=#ff8b16&gt;render&lt;/FONT&gt;(&lt;FONT color=#ff8b16&gt;Context&lt;/FONT&gt;({'var': 'hello'}))&lt;br /&gt;
u'hello -- HELLO -- False'&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t.&lt;FONT color=#ff8b16&gt;render&lt;/FONT&gt;(&lt;FONT color=#ff8b16&gt;Context&lt;/FONT&gt;({'var': '123'}))&lt;br /&gt;
u'123 -- 123 -- True'&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;주의할 점은 method를 호출하는데에 괄호를 사용하지 않았다는 점이다. method에 argument를 전달하는것은 가능하지 않다.&amp;nbsp; 즉, argument가 없는 경우에만 지원된다. (그 이유를 나중에 다시 설명하도록 한다)&lt;br /&gt;
&lt;br /&gt;마지막으로, '.'는 list index를 접근하는데에도 사용된다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;from django.template import Template, Context&lt;br /&gt;
&lt;/FONT&gt;&amp;gt;&amp;gt;&amp;gt; t = &lt;FONT color=#ff8b16&gt;Template&lt;/FONT&gt;('Item 2 is {{ items.2 }}.')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; c = &lt;FONT color=#ff8b16&gt;Context&lt;/FONT&gt;({'items': ['apples', 'bananas', 'carrots']})&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t.&lt;FONT color=#ff8b16&gt;render&lt;/FONT&gt;(c)&lt;br /&gt;
u'Item 2 is carrots.'&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;음수&amp;nbsp;index는 허용되지 않는다. 즉, {{ items.-1 }는 TemplateSyntaxError를 유발한다.&lt;br /&gt;
&lt;br /&gt;template system이 변수명에 '.'을 발견하면, 다음 항목에 대해 순서대로 찾기를 시도한다.&lt;br /&gt;

&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;Dictionary lookup (예, foo[&quot;bar&quot;])&lt;/LI&gt;
&lt;LI&gt;Attribute lookup (예, foo.bar)&lt;/LI&gt;
&lt;LI&gt;Method call (예, foo.bar())&lt;/LI&gt;
&lt;LI&gt;List-index lookup (예, foo[2])&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;즉, system은 처음으로 찾은 type에 대해 작업을 시도한다.&lt;br /&gt;
&lt;br /&gt;'.'은 여러 단계의 하부를 찾는다. 예를 들어, {{ persion.name.upper }}를 사용하고, dictionay에 persion['name']을 찾아 upper() method를 호출한다.&lt;br /&gt;
&lt;/P&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;from django.template import Template, Context&lt;br /&gt;
&lt;/FONT&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;person &lt;/FONT&gt;= {'name': 'Sally', 'age': '43'}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t = &lt;FONT color=#ff8b16&gt;Template&lt;/FONT&gt;('{{ person.name.upper }} is {{ person.age }} years old.')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; c = &lt;FONT color=#ff8b16&gt;Context&lt;/FONT&gt;({'person': person})&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t.&lt;FONT color=#ff8b16&gt;render&lt;/FONT&gt;(c)&lt;br /&gt;
u'SALLY is 43 years old.'&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;
&lt;FONT color=#2b8400&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;STRONG&gt;method 호출&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;br /&gt;
&lt;br /&gt;method 호출은 다른 type보다도 좀더 복잡하다. 이럴때의 유의할 점을 정리하였다.
&lt;P&gt;&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;method를 찾는 동안, method가 exception을 발생하였다면, exception이 silent_variable_failure attribute가 True가 아니라면 exception이 전달된다. 만일 exception에 silent_variable_failure attribute가 있다면 변수는 비어있는 문자열이 될 것이다. 아래예를 참고하시오.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; t = &lt;FONT color=#ff8b16&gt;Template&lt;/FONT&gt;(&quot;My name is {{ person.first_name }}.&quot;)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;class&lt;/STRONG&gt; &lt;/FONT&gt;PersonClass3:&lt;br /&gt;
&lt;/FONT&gt;...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;def&lt;/STRONG&gt; first_name(self):&lt;br /&gt;
&lt;/FONT&gt;...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;raise &lt;/STRONG&gt;AssertionError, &quot;foo&quot;&lt;br /&gt;
&lt;/FONT&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;p = PersonClass3()&lt;br /&gt;
&lt;/FONT&gt;&amp;gt;&amp;gt;&amp;gt; t.&lt;FONT color=#ff8b16&gt;render&lt;/FONT&gt;(&lt;FONT color=#ff8b16&gt;Context&lt;/FONT&gt;({&quot;person&quot;: p}))&lt;br /&gt;
Traceback (most recent call last):&lt;br /&gt;
...&lt;br /&gt;
AssertionError: foo&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;class&lt;/STRONG&gt; SilentAssertionError(AssertionError):&lt;br /&gt;
&lt;/FONT&gt;...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;FONT color=#ff8b16&gt;silent_variable_failure = True&lt;/FONT&gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;class&lt;/STRONG&gt; PersonClass4:&lt;br /&gt;
&lt;/FONT&gt;...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;def&lt;/STRONG&gt; first_name(self):&lt;br /&gt;
&lt;/FONT&gt;...&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;FONT color=#ff8b16&gt;&lt;FONT color=#ff8b16&gt;raise &lt;/FONT&gt;SilentAssertionError&lt;br /&gt;
&lt;/FONT&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;p = PersonClass4()&lt;br /&gt;
&lt;/FONT&gt;&amp;gt;&amp;gt;&amp;gt; t.&lt;FONT color=#ff8b16&gt;render&lt;/FONT&gt;(&lt;FONT color=#ff8b16&gt;Context&lt;/FONT&gt;({&quot;person&quot;: p}))&lt;br /&gt;
u'My name is .'&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;method 호출은 argument가 없는 경우에만 동작한다. 그렇지 않는 경우, 다음 type을 찾는다.&lt;/LI&gt;
&lt;LI&gt;명확하게도 몇개의 method는 부작용이 있고, 어리석을 수 있다. 심지어 보안 취약점이 있으며 template system을 access 하도록 허락된다.&lt;br /&gt;
&lt;br /&gt;예를 들어, BankAccount object는 delete() method를 가지고 있는데, {{ account.delete }}와 같이 templete가 구성되면 template가 render될 때 object는 삭제될 것이다.&lt;br /&gt;
&lt;br /&gt;이러한 것을 방지하기 위해, 함수 attribute로 alters_data를 다음과 같이 세팅한다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 304px; HEIGHT: 73px&quot; class=python cols=31 name=code&gt;def delete(self):
    # Delete the account
delete.alters_data = True
&lt;/TEXTAREA&gt;&lt;br /&gt;
template system은 이러한 방법&amp;nbsp;mark된&amp;nbsp;method를 실행하지 않는다. 위 예를 계속해서, 만약 template가 {{ account.delete }}를 포함하고 deleete() method가 alters_data=True가 있다면 delete() method는 template가 render 될때 실행되지 않고 조용히 실패하게 된다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;FONT color=#2b8400&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;STRONG&gt;무효한(invalid) 변수는 어떻게 처리되는가?&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;br /&gt;
&lt;br /&gt;기본으로 만약 변수가 존재하지 않는다면, template system은 비어있는 문자열로 render하고 조용히 실패한다. 아래는 그 예이다.&lt;br /&gt;
&lt;/P&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;from django.template import Template, Context&lt;br /&gt;
&lt;/FONT&gt;&amp;gt;&amp;gt;&amp;gt; t = &lt;FONT color=#ff8b16&gt;Template&lt;/FONT&gt;('Your name is {{ name }}.')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t.&lt;FONT color=#ff8b16&gt;render&lt;/FONT&gt;(Context())&lt;br /&gt;
u'Your name is .'&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t.&lt;FONT color=#ff8b16&gt;render&lt;/FONT&gt;(&lt;FONT color=#ff8b16&gt;Context&lt;/FONT&gt;({'var': 'hello'}))&lt;br /&gt;
u'Your name is .'&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t.&lt;FONT color=#ff8b16&gt;render&lt;/FONT&gt;(&lt;FONT color=#ff8b16&gt;Context&lt;/FONT&gt;({'NAME': 'hello'}))&lt;br /&gt;
u'Your name is .'&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; t.&lt;FONT color=#ff8b16&gt;render&lt;/FONT&gt;(&lt;FONT color=#ff8b16&gt;Context&lt;/FONT&gt;({'Name': 'hello'}))&lt;br /&gt;
u'Your name is .'&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;system은 exception을 발생하는 것보다 조용히 실패하는 것으로 되는데, 왜냐하면 human error에 대해 회복력이 있도록 하기 위함이다. 이러한 경우 모든 찾기에 대해 실패하는데 왜냐하면 변수명이 잘못되었기 때문이다. 현실에서, web site가 작고 단순한 template 문법 오류로 인해 전체가&amp;nbsp;접근이 되지 못하는 경우를 받아 들일 수 없기 때문이다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#2b8400&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;Context object로 장난하기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;대부분의 경우 미리 사전에 모두 생성된 dictionary를 Context()에 전달하여 Context object를 초기화한다. 그러나, 초기화 이후에도 다음과 같이 item을 추가/삭제할 수 있다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;from django.template import Context&lt;br /&gt;
&lt;/FONT&gt;&amp;gt;&amp;gt;&amp;gt; c = &lt;FONT color=#ff8b16&gt;Context&lt;/FONT&gt;({&quot;foo&quot;: &quot;bar&quot;})&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; c['foo']&lt;br /&gt;
'bar'&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;del &lt;/STRONG&gt;&lt;/FONT&gt;c['foo']&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; c['foo']&lt;br /&gt;
Traceback (most recent call last):&lt;br /&gt;
&amp;nbsp; ...&lt;br /&gt;
KeyError: 'foo'&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;c['newvariable'] &lt;STRONG&gt;=&lt;/STRONG&gt; 'hello'&lt;br /&gt;
&lt;/FONT&gt;&amp;gt;&amp;gt;&amp;gt; c['newvariable']&lt;br /&gt;
'hello'&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;
&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;Template tag와&amp;nbsp;Filter&amp;nbsp;기초&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;이미 언급했듯이, django의 tmeplate system은 built-in tag와 filter를 가지고 있다. 본 section은 가장 일반적으로 사용되는 tag와 filter에 대해 설명하도록 한다.&lt;br /&gt;
&lt;br /&gt;&lt;FONT color=#2b8400&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;tag&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#2b8400&gt;if/else&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;{% if %} tag는 변수값을 평가하고 그 값이 &quot;True&quot;이면 {% if %}와 {% endif %} 사이에 있는 모든것을 표시한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% if today_is_weekend %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;Welcome to the weekend!&amp;lt;/p&amp;gt;&lt;br /&gt;
{% endif %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;{% else %} tag는 옵션사항이다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% if today_is_weekend %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;Welcome to the weekend!&amp;lt;/p&amp;gt;&lt;br /&gt;
{% else %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;Get back to work.&amp;lt;/p&amp;gt;&lt;br /&gt;
{% endif %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#eaf4cf&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;100%&quot;&gt;Python의 &quot;Truthiness&quot;&lt;br /&gt;
&lt;br /&gt;django template system 그리고 python에서 다음 object는 Boolean의 False로 평가한다.&lt;br /&gt;

&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;비어있는 list ([])&lt;/LI&gt;
&lt;LI&gt;비어있는 tuple (())&lt;/LI&gt;
&lt;LI&gt;비어있는 dictionary ({})&lt;/LI&gt;
&lt;LI&gt;비어있는 문자열 ('')&lt;/LI&gt;
&lt;LI&gt;Zero (0)&lt;/LI&gt;
&lt;LI&gt;None object&lt;/LI&gt;
&lt;LI&gt;False object&lt;/LI&gt;
&lt;LI&gt;자신만의 Boolean context 행동을 정의한 custom object&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;그 이외는 모두 True로 평가한다.&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;{% if %} tag는 여러개의 변수를 테스트하는데 and, or, 혹은 not을 지원하고, 주어진 변수에 대한 부정을 할 수 있다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;{% if athlete_list and coach_list %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Both athletes and coaches are available.&lt;br /&gt;
{% endif %}&lt;/P&gt;
&lt;P&gt;{% if not athlete_list %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; There are no athletes.&lt;br /&gt;
{% endif %}&lt;/P&gt;
&lt;P&gt;{% if athlete_list or coach_list %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; There are some athletes or some coaches.&lt;br /&gt;
{% endif %}&lt;/P&gt;
&lt;P&gt;{% if not athlete_list or coach_list %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; There are no athletes or there are some coaches.&lt;br /&gt;
{% endif %}&lt;/P&gt;
&lt;P&gt;{% if athlete_list and not coach_list %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; There are some athletes and absolutely no coaches.&lt;br /&gt;
{% endif %}&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;{% if %} tag는 같은 tag에서 and 그리고 or를 섞어 쓰는것을 금지하고 있는데, 이는 logic의 순서의 애매성 발생을 금지하기 위해서이다. 예들 들어, 다음은 오류를 유발한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% if athlete_list and coach_list or cheerleader_list %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;순서를 정하기 위한 괄호사용은 지원되지 않는다. 만일 괄호사용이 필요하다면 template 밖에서 logic을 수행하고 그 결과를 template 변수로 전달하도록 한다. 혹은 다음과 같이 중첩된 {% if %} tag를 사용하기도 한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% if athlete_list %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {% if coach_list or cheerleader_list %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; We have athletes, and either coaches or cheerleaders!&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {% endif %}&lt;br /&gt;
{% endif %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;같은 논리 연산자를 여러개 동시에 사용하는것은 허락되나, 다른 종류는 불허한다. 다음은 허락된다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% if athlete_list or coach_list or parent_list or teacher_list %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;{% elif %} tag는 없다. 대신 중첩된 {% if %}를 사용하면 된다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% if athlete_list %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;Here are the athletes: {{ athlete_list }}.&amp;lt;/p&amp;gt;&lt;br /&gt;
{% else %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;No athletes are available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {% if coach_list %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;Here are the coaches: {{ coach_list }}.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {% endif %}&lt;br /&gt;
{% endif %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;각 {% if %}는 {% endif %}로 닫아져야함을 유념하자. 그렇지 않으면 TemplateSyntaxError를 유발한다.&lt;br /&gt;
&lt;br /&gt;&lt;FONT color=#2b8400&gt;&lt;STRONG&gt;for&lt;/STRONG&gt;&lt;/FONT&gt;&lt;br /&gt;
&lt;br /&gt;{% for %} tag는 연속적인(sequence) 각각의 item을 loop로 다루도록 해준다. python의 for statement 처럼, 문법은 for X in Y 와 같은데, Y는 loop를 위한 sequence이며, X는 loop에서 사용할 변수의 이름을 의미한다. loop 내의 각각의 시간동안 template system은 {% for %}와 {% endfor %} 사이의 모든것을 render 한다.&lt;br /&gt;
&lt;br /&gt;예를 들어, athlete_list의 모든 항목을 출력한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
{% for athlete in athlete_list %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;li&amp;gt;{{ athlete.name }}&amp;lt;/li&amp;gt;&lt;br /&gt;
{% endfor %}&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;reserved를 추가하면 list의 역방향으로 loop가 돌게된다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% for athlete in athlete_list reversed %}&lt;br /&gt;
...&lt;br /&gt;
{% endfor %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;중첩된 {% for %} tag는 가능하다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% for athlete in athlete_list %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;h1&amp;gt;{{ athlete.name }}&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {% for sport in athlete.sports_played %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;li&amp;gt;{{ sport }}&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {% endfor %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/ul&amp;gt;&lt;br /&gt;
{% endfor %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;loop 직전에 size를 체크하고 list가 비었다면 특별한 문장을 출력하는 일반적인 pattern은 다음과 같다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% if athlete_list %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {% for athlete in athlete_list %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;{{ athlete.name }}&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {% endfor %}&lt;br /&gt;
{% else %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;There are no athletes. Only computer programmers.&amp;lt;/p&amp;gt;&lt;br /&gt;
{% endif %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;이러한 pattern이 주로 사용되는데, {% empty %}를 이용하는 것이다. 아래는 위의 것과 동일하게 동작한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% for athlete in athlete_list %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;{{ athlete.name }}&amp;lt;/p&amp;gt;&lt;br /&gt;
{% empty %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;There are no athletes. Only computer programmers.&amp;lt;/p&amp;gt;&lt;br /&gt;
{% endfor %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;loop가 끝날때 까지 loop를 벗어나는 &quot;breaking out&quot;은 지원되지 않는다. 이것을 달성하고 싶다면, loop를 종결하기 위한 값을 변경하는 것이다. 이와 유사하게 &quot;continue&quot;를 통한 loop의 첫두로 돌아가는 것도 지원되지 않는다.&lt;br /&gt;
&lt;br /&gt;{% for %} loop 내부에서, forloop라는 임시 변수에 접근할 수 있다. 이 변수는 몇몇 attribute를 가지는데, loop의 진척도 정보를 제공한다.
&lt;P&gt;&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;forloop.counter는 loop에 들어간 횟수를 리턴한다. 이것은 1부터 시작하는 값이다. 그 예는 다음과 같다.&lt;br /&gt;

&lt;TABLE style=&quot;WIDTH: 573px; BORDER-COLLAPSE: collapse; HEIGHT: 60px&quot; cellSpacing=1 cellPadding=1 width=573 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% for item in todo_list %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;{{ forloop.counter }}: {{ item }}&amp;lt;/p&amp;gt;&lt;br /&gt;
{% endfor %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/LI&gt;
&lt;LI&gt;forloop.counter0는 forloop.count와 같지만, 0부터 시작한다.&lt;/LI&gt;
&lt;LI&gt;forloop.revcounter는 loop에서 남은 item의 개수를 알려준다. 만일 loop의 마지막이라면 forloop.revcount는 1이다.&lt;/LI&gt;
&lt;LI&gt;forloop.revcounter0은 forloop.revcount와 같지만, loop의 마지막이라면 forloop.revcount0은 0이다.&lt;/LI&gt;
&lt;LI&gt;forloop.first는 loop의 처음인 경우 True가 전달된다. 다음과 같은 경우 편리하게 사용된다.&lt;br /&gt;

&lt;TABLE style=&quot;WIDTH: 571px; BORDER-COLLAPSE: collapse; HEIGHT: 96px&quot; cellSpacing=1 cellPadding=1 width=571 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% for object in objects %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {% if forloop.first %}&amp;lt;li class=&quot;first&quot;&amp;gt;{% else %}&amp;lt;li&amp;gt;{% endif %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {{ object }}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/li&amp;gt;&lt;br /&gt;
{% endfor %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/LI&gt;
&lt;LI&gt;forloop.last는 loop의 마지막인 경우 True가 전달된다. 이것은 다음과 같이 link list간의 pipe 문자를 표시하는데 사용된다.&lt;br /&gt;

&lt;TABLE style=&quot;WIDTH: 574px; BORDER-COLLAPSE: collapse; HEIGHT: 24px&quot; cellSpacing=1 cellPadding=1 width=574 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% for link in links %}{{ link }}{% if not forloop.last %} | {% endif %}{% endfor %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;그럼 아래와 같이 표기된다.&lt;br /&gt;

&lt;TABLE style=&quot;WIDTH: 575px; BORDER-COLLAPSE: collapse; HEIGHT: 24px&quot; cellSpacing=1 cellPadding=1 width=575 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;Link1 | Link2 | Link3 | Link4&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;다른 유용한 사용은 다음과 같이 list에 ,를 표시할 때 이다.&lt;br /&gt;

&lt;TABLE style=&quot;WIDTH: 575px; BORDER-COLLAPSE: collapse; HEIGHT: 42px&quot; cellSpacing=1 cellPadding=1 width=575 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;Favorite places:&lt;br /&gt;
{% for p in places %}{{ p }}{% if not forloop.last %}, {% endif %}{% endfor %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/LI&gt;
&lt;LI&gt;forloop.parentloop는 중첩된 loop에서&amp;nbsp;&lt;EM&gt;부모&lt;/EM&gt; loop의 forloop object를 참조한다. 다음은 그 예이다.&lt;br /&gt;

&lt;TABLE style=&quot;WIDTH: 575px; BORDER-COLLAPSE: collapse; HEIGHT: 204px&quot; cellSpacing=1 cellPadding=1 width=575 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% for country in countries %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;table&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {% for city in country.city_list %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;td&amp;gt;Country #{{ forloop.parentloop.counter }}&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;td&amp;gt;City #{{ forloop.counter }}&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;td&amp;gt;{{ city }}&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {% endfor %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/table&amp;gt;&lt;br /&gt;
{% endfor %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;이와 같은 forloop 변수는 loop에서만 사용가능하다. {% endif %}를 만나면 forloop는 제거된다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#2b8400&gt;ifequal / ifnotequal&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;django template system은 python 구문을 단독을 실행시켜 줄 만큼의 program language는 아니다. 그러나, {% ifequal %} tag등을 이용하여 두개의 값을 비교하여 표시하는 방법은 제공하고 있다.&lt;br /&gt;
&lt;br /&gt;{% ifequal %} tag는 만일 값이 동일하다면 {% ifequal %}와 {% endequal %}&amp;nbsp; 사이의 모든 것을 출력한다.&lt;br /&gt;
&lt;br /&gt;다음은 그 예이다.&lt;br /&gt;
&lt;/P&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% ifequal user currentuser %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;h1&amp;gt;Welcome!&amp;lt;/h1&amp;gt;&lt;br /&gt;
{% endifequal %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;argument는 ' 혹은 &quot; 문자를 이용하여 hard-code된 문자열도 가능하다. 다음은 유효한 구문이다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;{% ifequal section 'sitenews' %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;h1&amp;gt;Site News&amp;lt;/h1&amp;gt;&lt;br /&gt;
{% endifequal %}&lt;/P&gt;
&lt;P&gt;{% ifequal section &quot;community&quot; %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;h1&amp;gt;Community&amp;lt;/h1&amp;gt;&lt;br /&gt;
{% endifequal %}&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;{% if&amp;nbsp;%}와 같이 {% ifequal %} tag는 옵션인 {% else %}를 지원한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% ifequal section 'sitenews' %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;h1&amp;gt;Site News&amp;lt;/h1&amp;gt;&lt;br /&gt;
{% else %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;h1&amp;gt;No News Here&amp;lt;/h1&amp;gt;&lt;br /&gt;
{% endifequal %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;template 변수, 문자열, 정수, 그리고 10진수 숫자등은 {% ifequal %}에서 지원된다. 다음은 유효하다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% ifequal variable 1 %}&lt;br /&gt;
{% ifequal variable 1.23 %}&lt;br /&gt;
{% ifequal variable 'foo' %}&lt;br /&gt;
{% ifequal variable &quot;foo&quot; %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;python의 dictionary, list, 혹은 Boolean과 같은 다른 type 형태는 사용할 수 없다. 다음은 유효하지 않다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% ifequal variable True %}&lt;br /&gt;
{% ifequal variable [1, 2, 3] %}&lt;br /&gt;
{% ifequal variable {'key': 'value'} %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;만일 true/false에 대한 검사를 하고싶다면, {% ifequal %} 대신 {% if %}를 사용하라.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#2b8400&gt;주석&lt;br /&gt;
&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
HTML 혹은 python에서 django template language는 주석을 허용한다. {# #}를 사용한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{# This is a comment #}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;이러한 주석은 render되지 않는다.&lt;br /&gt;
&lt;br /&gt;위와 같은 주석은 여러줄을 허용하지 않는다. 아래의 주석은 template 그대로 출력된다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;This is a {# this is not&lt;br /&gt;
a comment #}&lt;br /&gt;
test.&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;만일 여러줄을 사용하고 싶다면, {% comment %} tag를 사용한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% comment %}&lt;br /&gt;
This is a&lt;br /&gt;
multi-line comment.&lt;br /&gt;
{% endcomment %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;
&lt;STRONG&gt;&lt;FONT color=#2b8400&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;Filter&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;이전에서 잠시 설명했는데, template filter는 출력되기 전 간단하게 변수값을 변환하는 방법을 제공한다. filter는 pipe문자를 사용하는데, 다음의 예와 같다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{{ name|lower }}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;이는 {{ name }} 변수값을 출력하는데, 소문자로 변환하는 lower filter를 처리한후 출력된다.&lt;br /&gt;
&lt;br /&gt;filter는 &lt;EM&gt;이어질(chained)&lt;/EM&gt;수 있는데, 그 결과가 다음으로 적용된다. 다음은 list 첫 항목을 대문자로 변환한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{{ my_list|first|upper }}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;몇몇 filter는 argument를 받아들인다. :로 시작하며 항상 &quot;로 쌓여 있어야 한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{{ bio|truncatewords:&quot;30&quot; }}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;이는 bio 변수의 30 단어만 출력한다.&lt;br /&gt;
&lt;br /&gt;이외의 주요한 filter는 다음과 같다.
&lt;P&gt;&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;addslashes : &lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;\&lt;/SPAN&gt;, ', &quot; 앞에 &lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;\&lt;/SPAN&gt;문자를 추가한다. 이는 javascript 문자열을 포함하는데 유용하게 사용된다.&lt;/LI&gt;
&lt;LI&gt;date : date 혹은 datetime object를 주어진 format 문자열로 format한다.&lt;br /&gt;

&lt;TABLE style=&quot;WIDTH: 574px; BORDER-COLLAPSE: collapse; HEIGHT: 24px&quot; cellSpacing=1 cellPadding=1 width=574 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{{ pub_date|date:&quot;F j, Y&quot; }}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/LI&gt;
&lt;LI&gt;length : value의 length를 리턴한다. list인 경우 항목의 개수를 리턴하고, 문자열인 경우 문자 개수를 전달한다. (python의 __len__() method를 참조한다)&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;&lt;FONT color=#ff8b16&gt;철학과 제약&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;이제 django template language에서 몇몇의 철학에 따른 의도적인 제약에 대해 설명하고자 한다.&lt;br /&gt;
&lt;br /&gt;web application의 다른 component 이상으로 template syntax는 무척 주관적이고, programmer의 의견 또한 분분하다. python은 수십개의 open source template-language 구현을 가지고 있는데, 각각 모두 모든 template language의 부족한점이 있다고 개발자는 간주하였기 때문이다. (즉, 이는 모든 python 개발자는 자신만의 template language를 가지고 있다는 말이다!)&lt;br /&gt;
&lt;br /&gt;이런 생각을 가지고, django는 그것의 template language를 사용하는 것을 요구하지 않도록 되어 있다. 왜냐하면 django는 의도적으로 full-stack web framework으로 되어 있다. 그것은 web 생산적이길 원하는 개발자에게 필요한 모든 조각을 제공하는데, 다른 python template library 보다 django의 template system이 훨씬 몇배 &lt;EM&gt;더 편리&lt;/EM&gt;했기 때문이다. 그러나 그것은 엄격하게 요구된건 아니다. 이에 대해서는 다음장을 통해 확인할 것이다. 즉, django로 다른 template language를 사용하는것은 그리 어려운것은 아니다.&lt;br /&gt;
&lt;br /&gt;그래도 여전히 django의 template language로 작업하는것을 강력히 추천한다. template system은 World Online과 django를 만든이의 경험이 조합되어 만들어져, 그 뿌리를 두고 있다.&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;&lt;EM&gt;Business logic(비지니스 로직)은 presentation logic(표현 로직)에서 분리되어야 한다&lt;/EM&gt;. django의 개발자는 표현의 도구로 template system을 볼 것이다. template system은 이러한 기본적인 목표 넘어 있는 기능은 지원하지 않아야 한다.&lt;br /&gt;
&lt;br /&gt;이러한 이유로, django template에는 직접적인 python code를 넣을 수 없다. 모든 &quot;programming&quot;은 근본적으로 template tag가 무엇을 할 수 있는 것의 범위(scope)를 제약한다. 독단적인 custom template tag를 작성하는 것은 가능하나, 격이 다른 django template tag는 의도적으로 독단적인 python code 실행을 허락하지 않는다.&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;문법은 HTML/XML으로 부터 분리되어야 한다&lt;/EM&gt;. 비록 django의 template system이 HTML을 생산하는데 일차적으로 사용되는데, plain-text와 같은 non-HTML format에도 사용하도록 되어 있다. 몇몇 다른 template language는 XML 기반인데, 모든 template logic을 XML tag나 attribute로 놓고 진행하나 django는 d의도적으로 이 제약을 피했다. template를 작성하는데 유효한 XML을 요구한다는 것이 인간의 실수나 이해하기 어려운 오류 메시지등을 유발하기 때문이다. 그리고 XML 엔진은 처리하는데 큰 부하를 유발한다.&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Designer는 HTML code에 편안함을 느낀다고 가정한다&lt;/EM&gt;. template system은 Dreamweaver와 같은 WYSIWYG 편집기에서 보여지는대로 나타나도록 설계된것이 아니다. 그것은 너무한 제약사항이며 친숙한 문법은 아니다. django는 HTML을 직접 편집하는데 편안하게 할 수 있도록 기대한다.&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Designer는 python 개발자가 아닌 것으로 가정한다&lt;/EM&gt;. template system을 사용하는 개발자는 web page template는 programmer가 아닌 designer에 의해 작성되어야 한다고 인지하며, 그리하여 python 지식을 가정하지 않는다.&lt;br /&gt;
&lt;br /&gt;그러나, system은 역시 template를 생성할 python programmer로 구성된 작은 팀을 수용할 수 있도록 의도하기도 한다. raw python code를 작성하여 문법을 확장할 수 있는 방법을 제공한다.&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;새로운 programming language를 개발하는것이 목적이 아니다&lt;/EM&gt;. 충분한 프로그래밍풍의 기능을&amp;nbsp;제공하는 것인데, 분기문이라던지 loop등이 포함된다. 이는 표현하는데 관련된 결정을 구현하는데 필수적이기 때문이다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;view에서 template 사용하기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;template system을 사용하는 기초를 확인하였다. 이제 view를 생성하는 방법을 알아볼 것이다. mysite.views에 있는 current_datetime view를 상기해보아라. 이는 이전 chapter에서 다루었으며, 다음과 같은 모습을 보인다.&lt;br /&gt;
&lt;/P&gt;&lt;TEXTAREA style=&quot;WIDTH: 324px; HEIGHT: 146px&quot; class=python rows=4 cols=33 name=code&gt;from django.http import HttpResponse
import datetime

def current_datetime(request):
	now = datetime.datetime.now()
	html = &quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;It is now %s.&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&quot; % now
	return HttpResponse(html)&lt;/TEXTAREA&gt;&lt;br /&gt;
django의 template system을 사용하기 위해 view를 변경해 보자. 우선 다음과 같은 것을 생각해 볼 수 있다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 402px; HEIGHT: 194px&quot; class=python rows=4 cols=38 name=code&gt;from django.template import Template, Context
from django.http import HttpResponse
import datetime

def current_datetime(request):
	now = datetime.datetime.now()
	t = Template(&quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;It is now {{ current_date }}.&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&quot;)
	html = t.render(Context({'current_date': now}))
	return HttpResponse(html)&lt;/TEXTAREA&gt;&lt;br /&gt;
물론, template system을 사용하나 이번 chapter의 소개때 지목하기도 했던 문제를 해결하진 못하고 있다. 다시 말해, template는 여전히 python code에 내장되어 있다. 그래서 data와 표현의 분리를 진정으로 분리하는 것이 달성되지 않았다. 이제 template를 &lt;EM&gt;분리된 파일&lt;/EM&gt;에 놓고, view가 직접 load하는 것을 만들어 보자.&lt;br /&gt;
&lt;br /&gt;당신의 filesystem상의 어느곳에 template를 저장할 것인지를 우선 고려해야 하고, python의 built-in file 열기 기능을 이용하여 template의 내용을 읽도록 한다. 아래는 /home/djangouser/templates/mytemplate.html에 저장되어 있다고 가정하고 작성된 것이다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 434px; HEIGHT: 292px&quot; class=python rows=8 cols=42 name=code&gt;from django.template import Template, Context
from django.http import HttpResponse
import datetime

def current_datetime(request):
	now = datetime.datetime.now()
	# Simple way of using templates from the filesystem.
	# This is BAD because it doesn't account for missing files!
	fp = open('/home/djangouser/templates/mytemplate.html')
	t = Template(fp.read())
	fp.close()
	html = t.render(Context({'current_date': now}))
	return HttpResponse(html)&lt;/TEXTAREA&gt;&lt;br /&gt;
이러한 접근은 그러나 다음과 같은 이유로 그다지 매력적이지 않다.&lt;br /&gt;

&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;file이 없는 경우 처리할 수 없다. 만약 mytemplate.html이 존재하지 않거나 읽을 상태가 아니라면, open()는 IOError exception을 발생한다.&lt;/LI&gt;
&lt;LI&gt;template의 위치를 hard-code하게 된다. 만일 모든 view에 이런 논리를 적용한다면, template 위치까지도 복사해야 한다. 수많은 typing은 굳이 언급하지 않아도 알 것이다.&lt;/LI&gt;
&lt;LI&gt;끓고 있는 보일러 판을 포함하고 있다. open(), fp.read() 그리고 fp.close()이 template가 로드될때 마다 호출된다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;이러한 문제를 풀기 위해 &lt;EM&gt;template loading&lt;/EM&gt;과 &lt;EM&gt;template directory&lt;/EM&gt;를 사용한다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;Template Loading&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;django는 filesystem으로 부터 template를 load할때 사용되는 편리하고 강력한 API를 제공하는데, template-load 호출과 template 그 자체에 대한 중복된 부분을 제거하는데 그 목표를 두고 있다.&lt;br /&gt;
&lt;br /&gt;template-loading API를 사용하기 위해 저장된 template이 있는 위치를 framework에 알려줘야 한다. 이는 settings.py에 지정되어 있다.&lt;br /&gt;
&lt;br /&gt;settings.py에 TEMPLATE_DIRS setting을 찾을 수 있다. 기본적으로 비어있는 tuple로 되어 있는데, 다음과 같이 자동으로 생성된 주석을 포함하고 있다.&lt;br /&gt;
&lt;/P&gt;&lt;TEXTAREA style=&quot;WIDTH: 354px; HEIGHT: 164px&quot; class=python rows=6 cols=36 name=code&gt;TEMPLATE_DIRS = (
    # Put strings here, like &quot;/home/html/django_templates&quot; or &quot;C:/www/django/templates&quot;.
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
)&lt;/TEXTAREA&gt;&lt;br /&gt;
이러한 setting은 template를 찾는 mechanism에 알려진다. TEMPLATE_DIR에 당신이 저장한 template의 위치를 추가할 수 있다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 374px; HEIGHT: 80px&quot; class=python cols=39 name=code&gt;TEMPLATE_DIRS = (
    '/home/django/mysite/templates',
)&lt;/TEXTAREA&gt;&lt;br /&gt;
여기서 주목해야 할 점을 몇기 기술한다.&lt;br /&gt;

&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;원하는 directory를 작성할 수 있는데, web server가 동작하는 계정에 의해 읽을 수 있는 directory여야 한다. 만약 적당한 경로를 찾지 못하였다면 project 경로에 template를 만들것을 추천한다.&lt;/LI&gt;
&lt;LI&gt;만약 TEMPLATE_DIRS가 하나의 directory만 포함한다면, 마지막의 ,를 빼먹으면 안된다.&lt;/LI&gt;
&lt;LI&gt;만약 windows에서 동작한다면, &lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;\&lt;/SPAN&gt; 대신 /를 사용하도록 한다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 345px; HEIGHT: 64px&quot; class=python cols=36 name=code&gt;TEMPLATE_DIRS = (
	'C:/www/django/templates',
)&lt;/TEXTAREA&gt;&lt;/LI&gt;
&lt;LI&gt;절대 경롤ㄹ 이용하면 편리하다. 만약 보다 유연하고 느슨하게 결합되기를 바란다면, TEMPLATE_DIRS에 동적인 경로를 넣도록 하는 것이다. 다음과 같다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 373px; HEIGHT: 132px&quot; class=python cols=35 name=code&gt;import os.path

TEMPLATE_DIRS = (
	os.path.join(os.path.dirname(__file__), 'templates').replace('\\','/'),
)&lt;/TEXTAREA&gt;&lt;br /&gt;
이런 경우, __file__이라는 python의 변수를 사용하고 있는데, python 모듈의 경로를 자동으로 세팅해 준다. 즉, settings.py(os.path.dirname)을 포함하는 경로를 구하고, templates를 join한다(os.path.join). 그다음 &lt;SPAN style=&quot;FONT-FAMILY: Courier New&quot;&gt;\&lt;/SPAN&gt; 대신 /를 사용하도록 치환한다(windows인 경우).&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;TEMPLATE_DIRS가 세팅되었다면, 그 다음으로 django의 template load하는 부분을 기존의 hard-code된 것으로 부터 수정한다. current_datetime view로 돌아와서, 다음과 같이 수정해 보자.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 441px; HEIGHT: 196px&quot; class=python rows=4 cols=42 name=code&gt;from django.template.loader import get_template
from django.template import Context
from django.http import HttpResponse
import datetime

def current_datetime(request):
	now = datetime.datetime.now()
	t = get_template('current_datetime.html')
	html = t.render(Context({'current_date': now}))
	return HttpResponse(html)&lt;/TEXTAREA&gt;&lt;br /&gt;
본 예에서 django.template.loader.get_template()를 사용한다. get_template() 함수는 template 이름을 argument로 받고 filesystem에 있는 template를 찾고 open한 다음 그리고 compile된 Template object를 리턴한다.&lt;br /&gt;
&lt;br /&gt;본 예의 template는 current_datetime.html로 되어 있는데, 아직 별다른 .html 확장자의 파일도 없다. 확장자는 붙이거나 빼거나 해도 무방하다.&lt;br /&gt;
&lt;br /&gt;filesystem 상의 template의 위치 찾기를 결정하기 위해, get_template()는 TEMPLATE_DIRS의 경로와 get_template()에 전달한 template 이름을 결합한다. 예를 들어, TEMPLATE_DIRS이 '/home/django/mysite/templates'로 되어 있고 위 예처럼 get_template()가 호출하면 /home/django/mysite/templates/current_datetime.html를 찾게 된다.&lt;br /&gt;
&lt;br /&gt;만약 get_template()에서 주어진 이름으로 찾지 못했다면, TemplateDoesNotExist exception이 발생한다. 현재 위 예를 가지고 실험하면 아래와 같은 오류가 발생한다.&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile26.uf.tistory.com/original/17329D474F7E965135266F&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile26.uf.tistory.com/image/17329D474F7E965135266F&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;016.png&quot; height=&quot;507&quot; width=&quot;520&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
template directory에 아래와 같은 current_datetime.html을 생성하면 오류없이 실행된다.&lt;br /&gt;
&lt;/P&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;It is now {{ current_date }}.&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;
&lt;STRONG&gt;&lt;FONT color=#2b8400&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;render_to_response()&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;이제까지 template를 어떻게 load하는지를 보아왔다. 그것은 Context를 채우고 HttpResponse object를 rendered template 결과를 가지고 리턴한다. hard-coding된 template와 경로 대신에 get_template()를 사용하여 최적화 하였다. 그러나 여전히 몇가지가 요구되어 졌다. django는 template를 load, render, HttpResponse 리턴하는데 지름길을 제공한다. 즉, 모든것을 하나의 line으로 해결하는 것이다.&lt;br /&gt;
&lt;br /&gt;이러한 지름길이 render_to_response()로, django.shortcuts module에 있다. 대부분의 경우 template를 load하고 Context를 생성하고 HttpResponse object를 수동으로 생성하여 리턴하는등의 작업 대신 render_to_response()를 사용한다.&lt;br /&gt;
&lt;br /&gt;여기까지의 current_datetime 예제를 render_to_response()로 적용하면 아래와 같다.&lt;br /&gt;

&lt;P&gt;&lt;/P&gt;&lt;TEXTAREA style=&quot;WIDTH: 358px; HEIGHT: 172px&quot; class=python rows=5 cols=36 name=code&gt;from django.shortcuts import render_to_response
import datetime

def current_datetime(request):
	now = datetime.datetime.now()
	return render_to_response('current_datetime.html', {'current_date': now})&lt;/TEXTAREA&gt;&lt;br /&gt;
여태까지와 비교해서 변경된것은 다음과 같다.&lt;br /&gt;

&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;get_template, Template, Context, 혹은 HttpResponse를 import할 필요가 없다. 대신 django.shortcuts.render_to_response만 import한다. import datetime은 남아있다.&lt;/LI&gt;
&lt;LI&gt;current_datetime 함수에서 여전히 now를 계산하지만 template loading, context 생성, template rendering 그리고 HttpResponse 생성은 render_to_reponse() 호출에 의해 제거되었다.&lt;br /&gt;
render_to_response()는 HttpResponse object를 리턴하기 때문에, 간단히 view 함수의 리턴으로 사용할 수 있다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;render_to_reponse()의 첫 argument는 사용할 template의 이름이다. 두번째 argument는 만약 지정된다면, template를 위한 Context 생성에 사용될 dictionary이다. 만약 두번째 argument가 없다면, render_to_response()는 비어있는 dictionary를 사용한다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#2b8400&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;locals() 속임수&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;이제 마지막 current_datetime을 고려해 보자.&lt;br /&gt;
&lt;/P&gt;&lt;TEXTAREA style=&quot;WIDTH: 379px; HEIGHT: 108px&quot; class=python rows=4 cols=39 name=code&gt;def current_datetime(request):
	now = datetime.datetime.now()
	return render_to_response('current_datetime.html', {'current_date': now})&lt;/TEXTAREA&gt;&lt;br /&gt;
많은 경우, 주어진 예에서 몇몇 값을 계산하고, 변수에 저장하며 template에 전달한다. 게으른 programmer는 template 변수명을 위한 이름을 주는 것과 임시 변수를 위해 이름을 주는 것이 약간은 쓸모 없을 것으로 보여질 것이다. 쓸모 없을 뿐 아니라 추가적인 typing이라고 간주한다.&lt;br /&gt;
&lt;br /&gt;만약 당신이 게으른 programmer이고 축약된 code를 선호한다면, local()이라는 built-in python 함수를 사용할 수 있다. 그것은 지역(local) 변수와 값을 매핑한 dictionary를 리턴하는데, local 이라는 뜻은 현재 범위(scope)내에 정의된 변수들을 의미한다. 그래서 위의 코드는 다음과 같이 다시 작성될 수 있다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 393px; HEIGHT: 82px&quot; class=python rows=3 cols=42 name=code&gt;def current_datetime(request):
	current_date = datetime.datetime.now()
	return render_to_response('current_datetime.html', locals())&lt;/TEXTAREA&gt;&lt;br /&gt;
앞선 예와 같이 context dictionary를 수동으로 지정한 대신, local()을 사용하였는데, 함수의 실행 싯점의 정의된 모든 변수가 포함된다. 결과적으로 now 변수를 current_date로 이름을 변경하였는데, 이는 template가 예상하는 변수명이기 때문이다. 본 예에서, local()는&amp;nbsp;&lt;EM&gt;거대할&lt;/EM&gt;&amp;nbsp;정도로 향상을 가져오진 않는데, 다른 임시 변수의 사용을 줄일 수 있거나 게으를 때등, typing을 줄여주는 효과가 있다.&lt;br /&gt;
&lt;br /&gt;
&lt;DIV&gt;local()을 사용할 때 당신이 접근할 변수 이상의 모든 local 변수가 포함되어 있기 때문에 주의해서 사용해야 한다. 앞의 예에서 local()은 request를 역시 포함하고 있다. 이는 application과 완변성에 영향을 준다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;&lt;FONT color=#2b8400&gt;get_template()의 subdirectory 사용&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;template를 단일 경로로 사용되지 않는 경우도 많다. template directory의 하부 directory에 template를 저장하는 것을 선호할 수 있다. django에서도 이를 추천하며, 추후 11장에서 다룰 이러한 template layout을 기본 관습(convention)으로 간주한다.&lt;br /&gt;
&lt;br /&gt;template directory의 하부 directory를 지정하는 것은 간단하게 해결된다. get_template()에 하부 directory와 template 이름을 아래와 같이 명기하면 된다.&amp;nbsp;&lt;br /&gt;
&lt;TEXTAREA style=&quot;MARGIN: 1px; WIDTH: 382px; HEIGHT: 75px&quot; class=python name=code&gt;t = get_template('dateapp/current_datetime.html')&lt;/TEXTAREA&gt;&lt;br /&gt;
render_to_response()도 같은 논리로 접근할 수 있다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;MARGIN: 1px; WIDTH: 383px; HEIGHT: 95px&quot; class=python name=code&gt;return render_to_response('dateapp/current_datetime.html', {'current_date': now})&lt;/TEXTAREA&gt;&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;&lt;FONT color=#2b8400&gt;include template tag&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;여기까지 template-loading system을 살펴보았는데, {% include %}라는 built-in template tag의 장점을 살펴보기로 하자. 이 tag는 다른 template의 content를 포함하도록 도와준다. tag의 argument는 포함할 template 이름이며, 그 이름은 (따옴표로 쌓인)hard-code 혹은 변수가 가능하다. 여러개의 template중 동일한 것들을 모으고 {% include %}를 사용하여 이러한 중복을 제거할 수 있다.&lt;br /&gt;
&lt;br /&gt;아래는 nav.html이라는 template의 내용을 포함하는 예제이다. ' 혹은 &quot; 따옴표는 허용된다.&lt;br /&gt;
&lt;/DIV&gt;
&lt;DIV&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% include 'nav.html' %}&lt;br /&gt;
{% include &quot;nav.html&quot; %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;
&lt;DIV&gt;아래는 include/nav.html을 포함한다.&lt;br /&gt;
&lt;/DIV&gt;
&lt;DIV&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% include 'includes/nav.html' %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;
&lt;DIV&gt;이 예는 template_name이라는 변수가 가리키는 template를 포함하도록 한다.&lt;br /&gt;
&lt;/DIV&gt;
&lt;DIV&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;{% include template_name %}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;
&lt;DIV&gt;get_template() 처럼, template의 이름은 TEMPLATE_DIR로 부터 요구된 template 이름을 추가하여 결정된다.&lt;br /&gt;
&lt;br /&gt;포함된 template는 그것을 포함하는 template의 context와 함께 계산되어 진다. 예를 들면, 아래 두개의 예를 들 수 있다.&lt;br /&gt;
&lt;/DIV&gt;
&lt;DIV&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;# mypage.html&lt;/P&gt;
&lt;P&gt;&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
{% include &quot;includes/nav.html&quot; %}&lt;br /&gt;
&amp;lt;h1&amp;gt;{{ title }}&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;/P&gt;
&lt;P&gt;# includes/nav.html&lt;/P&gt;
&lt;P&gt;&amp;lt;div id=&quot;nav&quot;&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; You are in: {{ current_section }}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;
&lt;DIV&gt;만약 mypage.html을 current_section을 포함한 context로 render한다면, 예상한대로 &quot;포함(include)&quot;된&amp;nbsp;template안에 변수가 표시될 것이다.&lt;br /&gt;
&lt;br /&gt;만일, {% include %} tag 안의 주어진 template 이름이 발견되지 않는다면, django는 다음 두개중 하나를 실행한다.&lt;br /&gt;
&lt;/DIV&gt;
&lt;DIV&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;DEBUG가 True라면, TemplateDoesNotExist 예외가 발생하여 오류 page가 표시된다.&lt;/LI&gt;
&lt;LI&gt;DEBUG가 False라면, 아무것도 표기하지 않고 조용히 넘어간다.&lt;/LI&gt;&lt;/UL&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;Template Inheritance(상속)&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;br /&gt;
&lt;br /&gt;여태껏 봐왔던 template 예제는 매우 작은 HTML로 구성되었는데, 실제로는 규모의 HTML로 구성된 template system을 사용할 것이다. 이는 다음과 같은 공통된 web 개발 문제를 야기한다 : web site를 통틀어 sitewide navigation(사이트맵)과 같은 동일한 page 영역에 대해 불필요한 중복등을 제거할 순 없을까?&lt;br /&gt;
&lt;br /&gt;이 문제를 해결하기 위한 전통적인 방법은, &lt;EM&gt;server-side include&lt;/EM&gt;를 사용하는 것인데, 당신의 HTML page에 다른 web page를 그 안으로 &quot;포함(include)&quot;하여 놓도록 지시한다. django는 이러한 접근방법을 {% include %} template tag를 이용하여 지원한다. 그러나 이러한 문제를 풀기위한 다른 선호된 방법은 &lt;EM&gt;template inheritance&lt;/EM&gt;을 이용하는 것이다.&lt;br /&gt;
&lt;br /&gt;본질적으로 template inheritance는 당신 site의 모든 공통된 부분을 포함하는 &quot;뼈대(skeleton)&quot; template를 기반(base)을 만들게 하고, &quot;blocks&quot;라는 override 가능한 자식 template를 정의하도록 한다.&lt;br /&gt;
&lt;br /&gt;우리의 current_datetime view를 위해 template를 좀더 완성하여 본다. 다음은 current_datetime.html 파일이다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;&amp;lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01//EN&quot;&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;title&amp;gt;The current time&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;h1&amp;gt;My helpful timestamp site&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;It is now {{ current_date }}.&amp;lt;/p&amp;gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;hr&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;Thanks for visiting my site.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;좋아 보이나, 다른 view를 위한 template를 만들력고 한다면, 어떤일이 발생할 까? 다시 말해, chapter 3에서 공유된 hours_ahead view와 같은 경우이다. 만약 다음과 같이 HTML template를 만들어 보자.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;&amp;lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01//EN&quot;&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;title&amp;gt;Future time&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;h1&amp;gt;My helpful timestamp site&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;In {{ hour_offset }} hour(s), it will be {{ next_time }}.&amp;lt;/p&amp;gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;hr&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;Thanks for visiting my site.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;명확하게도 만은 수의 HTML이 복사될 것 같다. navigation bar, 몇개의 css, 그리고 몇몇 JavaScript가 포함된 일반적인 site를 만든다면 각 template에는 모든 종류의 HTML 중복을 포함하게 될 것이다.&lt;br /&gt;
&lt;br /&gt;server-side include 해결 방식은 각 template의 공통된 부분을 뽑아내고 그것의 개별적인 template로 저장하는데, 그것은 다른 template에 의해 포함되어 진다. header.html로 호출될 화면 윗 부분의 template를 만들어 보자.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;&amp;lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01//EN&quot;&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;footer.html로 호출될 화면 아랫 부분의 template를 만들어 보자.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;hr&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;Thanks for visiting my site.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;include 기반의 전략으로, header와 footer는 쉽게 만들어진다. 이제 중간 부분은데 이는 좀 지저분하다. 본 예에서, 각 page는 &amp;lt;h1&amp;gt;My helpful timestamp site&amp;lt;/h1&amp;gt;이 있는데, 이는 header.html로 들어가지 않았다. 그 이유는 각 page의 &amp;lt;title&amp;gt;...&amp;lt;/title&amp;gt;이 다르기 때문이다. 만약 &amp;lt;h1&amp;gt;을 header에 포함하였다면, &amp;lt;title&amp;gt;을 포함하게 되고, 그것을 각 page마다 어떻게 custom할 것인가?&lt;br /&gt;
&lt;br /&gt;django의 template inheritance system은 이러한 문제를 해결하려고 만들어졌다. 단순하게 server-side include를 뒤집은 것으로 생각하면 된다. 공통된 부분 조각을 정의하는 대신, 다른 부분을 정의하도록 한 것이다.&lt;br /&gt;
&lt;br /&gt;처음할일은, base template를 정의하는 것이다. 그것은 이후에 정의될 &lt;EM&gt;자식(child) templates&lt;/EM&gt;로 채워질 skeleton을 의미한다. 아래는 base template 예이다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;&amp;lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01//EN&quot;&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;title&amp;gt;{% block title %}{% endblock %}&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;h1&amp;gt;My helpful timestamp site&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {% block content %}{% endblock %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {% block footer %}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;hr&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;Thanks for visiting my site.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {% endblock %}&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;base.html로 저장된 이 template은 site에 있는 모든 page를 위해 사용된다. 여기에서 child template는 override, 혹은 추가 혹은 block의 내용을 남기는등의 작업을 하게된다.&lt;br /&gt;
&lt;br /&gt;여태껏 보지 못했던 {% block %} tag가 등장하는데, template의 부분을 child template가 override 해주도록 template engine에 알려준다.&lt;br /&gt;
&lt;br /&gt;이제 base template를 가졌으니, current_datetime.html을 만들어 보자.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;{% extends &quot;base.html&quot; %}&lt;/P&gt;
&lt;P&gt;{% block title %}The current time{% endblock %}&lt;/P&gt;
&lt;P&gt;{% block content %}&lt;br /&gt;
&amp;lt;p&amp;gt;It is now {{ current_date }}.&amp;lt;/p&amp;gt;&lt;br /&gt;
{% endblock %}&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;chapter 3으로 부터 hours_ahead view를 위한 template를 만들어 보자. 아래는 그 예이다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e6ecfe&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b1c4fc 1px solid; BORDER-LEFT: #b1c4fc 1px solid; BORDER-TOP: #b1c4fc 1px solid; BORDER-RIGHT: #b1c4fc 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;{% extends &quot;base.html&quot; %}&lt;/P&gt;
&lt;P&gt;{% block title %}Future time{% endblock %}&lt;/P&gt;
&lt;P&gt;{% block content %}&lt;br /&gt;
&amp;lt;p&amp;gt;In {{ hour_offset }} hour(s), it will be {{ next_time }}.&amp;lt;/p&amp;gt;&lt;br /&gt;
{% endblock %}&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;이제 좀더 아름다워 지지 않았는가? 각 template는 &lt;EM&gt;다른&lt;/EM&gt; 부분을 포함하도록 하였다. 더이상 중복되어 불필요한 부분은 필요없다. site 전반적인 design이 변경되었다면, base.html만 변경하면&amp;nbsp;되며, 모든 다른 template는 그 영향을 받게 된다.&lt;br /&gt;
&lt;br /&gt;이제 그 동작 방법을 알아보자. current_datetime.html을 load하면, template engine은 {% extends %} tag를 보게 되고 이 template는 child template임을 인지한다. engine은 즉각 부모 template인 base.html을 load한다.&lt;br /&gt;
&lt;br /&gt;이때 template engine은 base.html에 3개의 {% block %} tag를 발견하고 child template의 내용과 교환하게 된다. 그래서 {% block title %}에서 정의한 title은 사용되고, 역시 {% block content %}도 그러하다.&lt;br /&gt;
&lt;br /&gt;child template는 footer block이 정의되지 않음을 주목하라. parent template로 부터 값을 대신한다. parent template의 {% block %} tag에 있는 내용(content)은 만일을 위한 대비책으로 들어간 것이다.&lt;br /&gt;
&lt;br /&gt;inheritance는 template context에 영향을 주진 않는다.&amp;nbsp;다시 말해 inheritance tree 상의 어떤 template은 모든 context로 부터 변수값에 대한 접근이 가능하다.&lt;br /&gt;
&lt;br /&gt;필여한 만큼 많은 level의 inheritance를 사용할 수 있다. inheritance를 사용하기 위한 다음의 3가지 level의 접근법이 일반적이다.&lt;/P&gt;
&lt;OL style=&quot;LIST-STYLE-TYPE: decimal&quot;&gt;
&lt;LI&gt;당신 site의 look-and-feel을 가지는 base.html을 생성한다. 이것은 거의 변경되지 않아야 한다.&lt;/LI&gt;
&lt;LI&gt;당신 site의 각 &quot;section&quot;에 들어갈 base_SECTION.html template를 생성한다(예, base_photos.html 그리고 base_forum.html). 이러한 template는 base.html을 확장(extend)하고 section별로 style/design을 포함한다.&lt;/LI&gt;
&lt;LI&gt;page 각 type을 위한 개별 template를 생성한다. 이는 forum page나 photo gallery와 같을 것이다. 이 template는 section template를 확장(extend)한다.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;이러한 접근법은 code 재활용성을 최대화하고 공유된 영역에 대해 손쉽게 추가할 수 있도록 한다.&lt;br /&gt;
&lt;br /&gt;template inheritance를 가지고 작업하는 몇가지 guideline을 공유한다.&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;{% extents %}를 사용하고자 한다면, template에 있는 첫 부분에 넣도록 하라. 그렇지 않으면 동작하지 않는다.&lt;/LI&gt;
&lt;LI&gt;일반적으로 {% block %} tag가 많으면 많을수록 좋다. child template는 모든 parent block을 재정의할 필요는 없다. 그래서 적당하게 기본적인 block만 채워넣는다.&lt;/LI&gt;
&lt;LI&gt;template에서 code가 중복되고 있다면, parent template에 {% block %}로 이동하자.&lt;/LI&gt;
&lt;LI&gt;parent template으로 부터 block의 내용을 구할 필요가 있다면, {{ block.super }}를 이용한다. 이는 parent template의 render된 text를 제공하여 준다. 이는 전체를 재정의하는 대신 일부를 추가할 때 유용하게 사용된다.&lt;/LI&gt;
&lt;LI&gt;동일한 이름의 여러개의 {% block %} tag를 정의하지 않도록 한다. 이 제약은 &quot;양쪽(both)&quot;의 방향에서 동작해야 하기 때문이다. block tag는 채워질 구멍을 제공하는 것 뿐만 아니라, &lt;EM&gt;부모(parent)&lt;/EM&gt;의 구멍을 채우기도 하기 때문이다. 2개의 동일한 이름의 {% block %}이 있다면, template의 parent는 어떤 block을 사용해야 할 지 모른다.&lt;/LI&gt;
&lt;LI&gt;{% extends %}로 전달된 template는 get_template() 사용에 의해 load된다. 다시 말해, TEMPLATE_DIRS setting에 추가된 이름이어야 한다.&lt;/LI&gt;
&lt;LI&gt;대부분의 겨우 {% extands %}에 들어가는 argument는 문자열이여야 하는데, 변수값도 가능하여 parent 이름도 runtime에 결정될 수 있어, 멋지게 동적인 것을 만들게 해준다.&lt;/LI&gt;&lt;/UL&gt;&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-124-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-124-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=27909443&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/124&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/django&quot;&gt;django&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/django/the%20django%20book%20study&quot;&gt;the django book study&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/126&quot; &gt;[06] django admin site&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(2)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/27&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/125&quot; &gt;[05] django의 model&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(1)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/124&quot; &gt;[04] django의 template&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(2)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/123&quot; &gt;[03] django 1.4의 view와 urlconfs&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/04&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/122&quot; &gt;[02] django 1.4 설치와 project 생성하기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/120&quot; &gt;[01] django 소개&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/28&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>the django book study</category>
			<category>context</category>
			<category>django</category>
			<category>template</category>
			<category>View</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/124</guid>
			<comments>http://greenfishblog.tistory.com/124#entry124comment</comments>
			<pubDate>Thu, 05 Apr 2012 10:47:17 +0900</pubDate>
		</item>
		<item>
			<title>[03] django 1.4의 view와 urlconfs</title>
			<link>http://greenfishblog.tistory.com/123</link>
			<description>&lt;P&gt;원문 : &lt;A href=&quot;http://www.djangobook.com/en/2.0/chapter03/&quot;&gt;http://www.djangobook.com/en/2.0/chapter03/&lt;/A&gt;&amp;nbsp;참고&lt;br /&gt;
&lt;br /&gt;&lt;SPAN style=&quot;FONT-SIZE: 18pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;django로&amp;nbsp;&quot;Hello world&quot;&amp;nbsp;page 출력하기&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;br /&gt;
&lt;br /&gt;web framework없이 Hello world를 출력하려면 단순히 &quot;Hello world&quot;만 있는 hello.html이라는 text file가 있으면 되는데, 이는 contents(&quot;Hello World&quot;)와 URL(&lt;A href=&quot;http://www.example.com/hello.html&quot;&gt;http://www.example.com/hello.html&lt;/A&gt;), 즉 2개로 구성된다.&lt;br /&gt;
&lt;br /&gt;django로는 두 개로 구성된 그 자체는 같지만, 다른 방법으로 지정한다. page의 contents는 &lt;EM&gt;view function&lt;/EM&gt;, 그리고, URL은 &lt;EM&gt;URLconf&lt;/EM&gt;에 의해 만들어진다.&lt;br /&gt;
&lt;br /&gt;아래 코드는&amp;nbsp;mysite(&lt;A href=&quot;http://greenfishblog.tistory.com/122&quot; target=_blank&gt;2012/03/30 - [django] - django 설치와 project 생성하기&lt;/A&gt;)의 연장선상에 있음을 참고하라.&lt;br /&gt;
&lt;br /&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;&lt;STRONG&gt;&lt;FONT color=#2b8400&gt;첫번째&amp;nbsp;View&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;br /&gt;
&lt;br /&gt;mysite 경로에 다음과 같은 views.py를 넣는다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 594px; HEIGHT: 63px&quot; class=python rows=1 cols=58 name=code&gt;from django.http import HttpResponse
def hello(request):
	return HttpResponse(&quot;Hello world&quot;)&lt;/TEXTAREA&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile2.uf.tistory.com/original/17012C384F75509E0FCFA1&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile2.uf.tistory.com/image/17012C384F75509E0FCFA1&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;001.png&quot; height=&quot;134&quot; width=&quot;273&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;우선, django.http module에 있는 HttpResponse class를 import 하고 있다.&lt;br /&gt;
이는 다음 코드에 필요한 class를 import하기 위해서이다.&lt;/LI&gt;
&lt;LI&gt;다음으로 hello 이름의 view 함수를 정의하고 있다.&lt;br /&gt;
각 view 함수는 request라는 parameter를 가지게 된다.&amp;nbsp;&lt;br /&gt;
view를 작동할 request에 대한 정보를 표현할 object로, django.http.HttpRequest class의 instance이다.&lt;br /&gt;
함수의 이름은 신경쓸 필요는 없으며, 특별한 규정도 없다.&lt;/LI&gt;
&lt;LI&gt;함수는 단순히 1줄로 구성되며, &quot;Hello world&quot;를 전달하여 생성된 HttpResponse class object를 리턴할 뿐이다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;&lt;FONT color=#2b8400&gt;&lt;br /&gt;
처음으로 URLconf 해보기&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;여기까지 작업한 후, python manage.py runserver하여 테스트하면, 다음과 같이 어디에서도 &quot;Hello world&quot;가 표시되지 않는다.&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile27.uf.tistory.com/original/153CFF3D4F755722034107&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile27.uf.tistory.com/image/153CFF3D4F755722034107&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;004.png&quot; height=&quot;237&quot; width=&quot;250&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
이는 아직 우리가만든 hello view를 모르기 때문이다. 그래서 해당 hello view를 특정 url과 연결하는 과정이 필요하다. URLconf를 이용하여 이러한 연결 과정을 수행한다.&lt;br /&gt;
&lt;br /&gt;&lt;EM&gt;URLconf&lt;/EM&gt;는 책의 목차와 비슷하다. 즉, &quot;이 url은 이 code, 저 url은 저 code를 각각 실행하라&quot;와 같은 방식이다. 예를 들어 &quot;/foo/를 접근할 때는 views.py라는 python module에 있는 foo_view()라는 view function을 호출해라.&quot;를 수행한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;br /&gt;
framework에 의해 만들어진 초기 urls.py는 다음과 같다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 609px; HEIGHT: 195px&quot; class=python rows=1 cols=49 name=code&gt;from django.conf.urls import patterns, include, url
# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()urlpatterns = patterns('',    
# Examples:    
# url(r'^$', 'mysite.views.home', name='home'),    
# url(r'^mysite/', include('mysite.foo.urls')),    
# Uncomment the admin/doc line below to enable admin documentation:    
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),    
# Uncomment the next line to enable the admin:    
# url(r'^admin/', include(admin.site.urls)),)&lt;/TEXTAREA&gt;&lt;br /&gt;
해당 코드는 주로 사용되는 code를 주석으로 처리해 놓아, 필요시 주석을 풀어 사용하면 된다.&lt;br /&gt;
일단, 다음과 같이 urls.py를 수정해 보자.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 616px; HEIGHT: 67px&quot; class=python rows=3 cols=66 name=code&gt;from django.conf.urls.defaults import *
urlpatterns = patterns('',
)&lt;/TEXTAREA&gt; &lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;첫줄은 django.conf.urls.defaults module를 import하도록 한다. 여기에서는 patterns 이라는 함수를 include한다&lt;/LI&gt;
&lt;LI&gt;두번째줄은 urlpatterns 변수에 patterns 함수의 수행 결과를 저장한다. patterns 함수는 빈 문자열을 전달할 뿐이다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;urlpatterns 변수가 주요한 값인데, 이는 django가 당신의 URLconf module을 찾는데 사용되기 때문이다. 이 변수는 url과 해당 url을 처리할 code간의 mapping을 정의한다. 위에서 보듯이 현재 URLconf는 비어있다. 이는 django application은 blank state로 된다.&lt;br /&gt;
url과 view를 추가하기 위해 아래와 같이 수정하면 된다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 610px; HEIGHT: 107px&quot; class=python rows=1 cols=61 name=code&gt;from django.conf.urls import *
from mysite.views import hello

urlpatterns = patterns('',
	('^hello/$', hello),
)&lt;/TEXTAREA&gt;&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;mysite/views.py module로 부터 hello view를 import하는데, 그것은 mysite.views라는 python 문법으로 표현하였다.&lt;/LI&gt;
&lt;LI&gt;('^hello/$', hello)를 urlpatterns에 추가하였는데, 정규표현식으로 pattern-matching으로 구성된 python tuple로 이뤄졌다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;이제 이를 가지고 다음과 같이 테스트한다.&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile6.uf.tistory.com/original/1169B0334F7551B7223FF5&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile6.uf.tistory.com/image/1169B0334F7551B7223FF5&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;002.png&quot; height=&quot;288&quot; width=&quot;514&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
404오류가 발생하였다.&lt;br /&gt;
눈치 빠르신 분은 확인하셨겠지만, 다음과 같이 URL에 /hello를 붙이면 원하는 Hello world가 출력된다.&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile22.uf.tistory.com/original/137A6E4B4F75523F294AF3&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile22.uf.tistory.com/image/137A6E4B4F75523F294AF3&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;003.png&quot; height=&quot;70&quot; width=&quot;263&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
물론, /Hello하면 역시 404오류가 발생한다.&lt;br /&gt;
&lt;br /&gt;이제부터 URLpattern의 문법을 확인해 볼 차례이다. /hello/ url로 맞추기원하는데, pattern은 그것과는 조금 다르게 보인다. 그이유는 다음과 같다.&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;django는 incomming url의 매번 처음 나타나는 '/' 문자는 제거한다. 그렇기 때문에 URLpattern을 설명할 때 /hello/ 처럼 시작하는 '/'를 붙이지 않게 된다.&lt;/LI&gt;
&lt;LI&gt;pattern은 '^'과 '$' 문자를 포함한다. 이는 다음의 특수한 의미를 가지는 정규 표현식 문자이다.&lt;br /&gt;
'^'는 문자열의 시작에 대한 pattern을 검사한다. 그리고 '$'는 문자열의 마지막의 pattern이 맞는지 검사한다.&lt;br /&gt;
&lt;br /&gt;예를 들어 설명하자면, 끝에 $가 없는 &quot;^hello/&quot;는 /hello/로 시작하는&amp;nbsp;모든 URL들에 대해 연결시킨다. 예를 들면 /hello/foo와 /hello/bar가 포함되며, /hello/는 포함되지 않는다. 유사하게 ^가 없는 &quot;hello/$&quot;와 같은 경우는 hello/로 끝나는&amp;nbsp;모든 URL들에 대해 연결시킨다. 예를 들어 /foo/bar/hello/와 같다. 만일, &quot;hello/&quot;와 같이 사용하였다면 hello/를 포함하는&amp;nbsp;모든&amp;nbsp;URL을 연결한다. 예를 들어, /foo/hello/bar와 같다. 그리고 더 이상, 더 이하도 아닌 /hello/로만 일치시키는데는 &quot;^hello/$&quot;를 사용한다.&lt;br /&gt;
&lt;br /&gt;대부분의 URLpattern은 ^$를 사용하는데, 보다 더 정제된 연결을 위해서 유연성을 가질 필요가 있다.&lt;br /&gt;
&lt;br /&gt;만일 누군가가 /hello와 같이 요청하였다면 끝에 /로 끝나지 않았기 때문에 어떤것도 연결되지 않을 것이다. 이유는 우리의 URLpattern은 /로 끝나기를 요구하기 때문이다. 그러나 끝에 /가 없더라도 같은 URL에 re-direct되는 것이 보다 일반적이다. (이는 django setting의 APPEND_SLASH를 사용하기도 한다)&lt;br /&gt;
&lt;br /&gt;만일 URL 끝의 /를 선호하는 사람(django 개발자)라면, URLpattern 끝에 /를 넣고 APPEND_SLASH에 True값을 전달한다. 만일 그렇지 않은 경우라면 URLpattern 끝에 /를 넣고 APPEND_SLASH에 False값을 전달한다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;그다음 URLconf에 대해 주목할 것은,&amp;nbsp;직접적인 호출없이 hello view 함수를 전달한 것이다. 이것은 python의 주요 기능중 하나로, 함수는&amp;nbsp;최상위 object인데, 이는 다른 어떤 변수와 같이 전달할 수 있음을 의미한다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e8e8e8&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #e8e8e8 1px solid; BORDER-LEFT: #e8e8e8 1px solid; BORDER-TOP: #e8e8e8 1px solid; BORDER-RIGHT: #e8e8e8 1px solid&quot; width=&quot;100%&quot;&gt;Regular Express&lt;br /&gt;
&lt;br /&gt;&lt;EM&gt;Regular express&lt;/EM&gt;(혹은 regexes)는 text의 pattern을 설명하는데 쓰인다. django의 URLconf는 강력한 URL 연결을 위해 독단적인 regexes를 사용한다. 일단 몇개의 regex symbol로 연습할 수 있다. 일반적인 symbol은 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e8e8e8&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;Symbol&lt;/SPAN&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;내용&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;모든 단일 문자&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;\d&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;모든 단일 숫자&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;[A-Z]&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;모든 대문자(A~Z)&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;[a-z]&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;모든 소문자(a~z)&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;[A-Za-z]&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;모든 대소문자 구별없는 문자(a~z 혹은 A~Z]&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;+&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;이전 표현이 하나 이상 연결(\d+는 하나 이상의 숫자)&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;[^/]+&lt;/SPAN&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;첫 /가 나타날때까지의 하나이상의 문자&lt;/SPAN&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;?&lt;/SPAN&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;0&amp;nbsp;혹은 하나의 이전 표현(\d?는 0 혹은 숫자 한 글자)&lt;/SPAN&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;*&lt;/SPAN&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;0 혹은 하나 이상의 이전 표현(\d*는 0 혹은 숫자 한글자 이상)&lt;/SPAN&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;{1,3}&lt;/SPAN&gt;&lt;/TD&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #c2c2c2 1px solid; BORDER-LEFT: #c2c2c2 1px solid; BORDER-TOP: #c2c2c2 1px solid; BORDER-RIGHT: #c2c2c2 1px solid&quot; width=&quot;50%&quot;&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;이전 표현의 1~3개 연결(\d[1,3]은 숫자 1,2,3글자)&lt;/SPAN&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;
보다 많은 정보는 &lt;A href=&quot;http://www.djangoproject.com/r/python/re-module/&quot;&gt;http://www.djangoproject.com/r/python/re-module/&lt;/A&gt;&amp;nbsp;참고 바람&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;
&lt;STRONG&gt;&lt;FONT color=#2b8400&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;404 오류에 대한 정보&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;현재까지 우리는 URLconf에 대해 단지 하나의 URLpattern을 정의하였다. 만일 다른 URL에 대한 요청시 어떤일이 일어 나는가?&lt;br /&gt;
&lt;br /&gt;&lt;A href=&quot;http://127.0.0.1:8000/goodbye/&quot;&gt;http://127.0.0.1:8000/goodbye/&lt;/A&gt; 혹은 &lt;A href=&quot;http://127.0.0.1:8000/hello/subdirectory/&quot;&gt;http://127.0.0.1:8000/hello/subdirectory/&lt;/A&gt; 혹은 site root인 &lt;A href=&quot;http://127.0.0.1:8000/&quot;&gt;http://127.0.0.1:8000/&lt;/A&gt;을 방문하는 것으로 해보자. 그럼 본 글의 윗 부분에서 설명된 Page not found 오류화면이 발생할 것이다.&lt;br /&gt;
&lt;br /&gt;해당 화면의 용도는 기본적인 404 오류 메시지의 수준을 넘어선다. URLconf의 모든 pattern을 알려주는데, 왜 404를 던지게 되었는지에 대해 설명한다.&lt;br /&gt;
&lt;br /&gt;해당 정보는 물론 당신 즉 web 개발자에게만 유용한 민감한 정보일 수 있다. 만일 internet 상으로 deploy되는 경우, 해당 정보를 공개되어 노출되지 않기를 원할 것이다. 그러한 이유로 &quot;Page not found&quot; url은 &lt;EM&gt;debug mode&lt;/EM&gt;인 경우에만 표시되도록 되어 있다. 이러한 debug mode를 off하는 방법은 추후 설명한다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;&lt;FONT color=#2b8400&gt;site root에 관한 정보&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;이전 section에서 site root에 대해 404 오류 메시지를 확인하였다. django는 site root에 대해 어떠한 장치를 해놓진 않는다. URLpattern에 단지 할당하기에 달려있다.&lt;br /&gt;
&lt;br /&gt;site root를 URLpattern에 추가하는게 직관적이고 쉽진 않는데, 다음과 같이 empty string을 통해 적용할 수 있다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 635px; HEIGHT: 112px&quot; class=python rows=1 cols=64 name=code&gt;from mysite.views import hello, my_homepage_view

urlpatterns = patterns('',
    ('^$', my_homepage_view),
    # ...
)&lt;/TEXTAREA&gt;&lt;br /&gt;
&lt;br /&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;&lt;STRONG&gt;django의 request 처리 방식&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;br /&gt;
&lt;br /&gt;우리의 두번째 view 함수에서 계속하여, 잠시 django가 어떻게 처리하는지를 배워보도록 하자.&lt;br /&gt;
특수하게도 &lt;A href=&quot;http://127.0.0.1:8000/hello/&quot;&gt;http://127.0.0.1:8000/hello/&lt;/A&gt;의 방문에 의해 &quot;Hello world&quot; 메시지를 브라우져에서 볼때 , django는 뒤에선 어떤 일을 하는 것인가?&lt;br /&gt;
&lt;br /&gt;모든것은 &lt;EM&gt;settings&lt;/EM&gt; 파일로 부터&amp;nbsp;시작한다. python manage.py runserver를 실행하면 해당 script는 settings.py를 찾는다. 해당 파일은 TEMPLATE_DIRS, DATABASE_NAME등등과 같은 대문자로 이뤄진 django project의 특정 설정을 포함한다. 가장 중요한 설정은 ROOT_URLCONF.ROOT_URLCONF로, web site에서 URLconf로 사용할&amp;nbsp;python mondule중&amp;nbsp;어떤것을 사용할지를 알려준다.&lt;br /&gt;
&lt;br /&gt;django-admin.py startproject가 settings.py와 url.py를 언제 생성하는지 살펴보아라. 자동생성된 settings.py의 ROOT_URLCONF는 자동 생성된 urls.py를 지목하고 있다. settings.py file을 열어보면 아래부분을 확인할 수 있다.&lt;br /&gt;
&lt;br /&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e8e8e8&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #dadada 1px solid; BORDER-LEFT: #dadada 1px solid; BORDER-TOP: #dadada 1px solid; BORDER-RIGHT: #dadada 1px solid&quot; width=&quot;100%&quot;&gt;...&lt;br /&gt;
ROOT_URLCONF = 'mysite.urls'&lt;br /&gt;
...&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;
이는 mysilte/urls.py를 사용하겠다는 뜻이다.&lt;br /&gt;
&lt;br /&gt;/hello/와 같은 특정 url에 대해 요청(request)이 들어오면, django는 ROOT_URLCONF 설정에 의해 지명된 URLconf를 load한다. 그다음, 그 URLconf에 있는 각각의 URLpattens를 순서대로 한번에 체크하는데, 일치하는것을 찾을때 까지 지속된다.&amp;nbsp;일치되는 것을 찾았다면, 해당 pattern과 연결된 view 함수를 호출하고, HttpReqeust object를 전달한다.&lt;br /&gt;
&lt;br /&gt;앞선 예로 보았듯이, view 함수는 HttpResponse를 리턴해야 한다. 그뒤 django는 그 python object를 적합한 HTTP header들과 body로 구성된 web response로 변환한다.&lt;br /&gt;
&lt;br /&gt;요약:&lt;/P&gt;
&lt;OL style=&quot;LIST-STYLE-TYPE: decimal&quot;&gt;
&lt;LI&gt;/hello/ 요청(request)이 들어왔다.&lt;/LI&gt;
&lt;LI&gt;ROOT_URLCONF 설정을 찾아 root URLconf를 구한다.&lt;/LI&gt;
&lt;LI&gt;/hello/ 와 처음으로 일치하는 URLpattern을 URLconf에서 찾는다.&lt;/LI&gt;
&lt;LI&gt;찾았다면, 연결된 view 함수를 호출한다.&lt;/LI&gt;
&lt;LI&gt;view 함수는 HttpResponse를 리턴한다.&lt;/LI&gt;
&lt;LI&gt;HttpResponse를 적합한 HTTP response로 변환하고, web page로 결과 보고 한다.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;이제 django에 의해 page가 생성되는 기본적인 과정을 알게 되었을 것이다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;&lt;FONT color=#ff8b16&gt;두번째 view : Dynamic Content&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;우리의 &quot;Hello world&quot; view는 django의 기본적인 동자을 확인하는데는 유용할 것이다. 그러나 web page를 동적으로 표현하는 경우네는 적합하지 않는데, 항상 같은 page만 보여주기 때문이다. 즉, static HTML file과 같이 동작한다.&lt;br /&gt;
&lt;br /&gt;두번째 view로,&amp;nbsp;현재의 시각을 표시하도록 동적인 것을 만들어 보자. 이는 매우 좋고 단순한데, 왜냐하면, 어떠한 database나 사용자 input이 연관되어 있지 않기 때문이다. 단지 server의 시각을 출력할 뿐이다. 그것은 &quot;Hello world&quot;만 출력하는것보다 훨씬 흥미로운데, 단지 조금 새로운 concept만 추가되었을 뿐이다.&lt;br /&gt;
&lt;br /&gt;이러한 view는 현재 시각의 측정과 HttpResponse를 리턴하는것과으로 두가지를 필요로 한다. python에 익숙하다면, datetime이라는 python module을 포함하면 시각을 계산할 수 있다. 다음과 같다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;import&lt;/STRONG&gt; datetime&lt;/FONT&gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;now &lt;/FONT&gt;= &lt;FONT color=#ff8b16&gt;datetime.datetime.now&lt;/FONT&gt;()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;now&lt;/FONT&gt;&lt;br /&gt;
datetime.datetime(2012, 4, 3, 10, 34, 31, 118000)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;print &lt;/STRONG&gt;now&lt;/FONT&gt;&lt;br /&gt;
2012-04-03 10:34:31.118000&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;django에서 현재 시각을 출력하기 위해, 다음과 같이 view를 만들고 HttpResponse를 리턴한다. 다음을 확인하라.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 608px; HEIGHT: 137px&quot; class=python rows=3 cols=62 name=code&gt;from django.http import HttpResponse
import datetime

def current_datetime(request):
	now = datetime.datetime.now()	
	html = &quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;It is now %s.&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&quot; % now	
	return HttpResponse(html)
&lt;/TEXTAREA&gt;&lt;br /&gt;
이는 우리의 hello view 함수인 views.py에 포함시키도록 한다. 간결성을 위해 이전의 hello 함수는 숨겼다. 그럼 전체 views.py는 다음과 같다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 613px; HEIGHT: 173px&quot; class=python rows=5 cols=60 name=code&gt;from django.http import HttpResponse
import datetime

def hello(request):
	return HttpResponse(&quot;Hello world&quot;)

def current_datetime(request):
	now = datetime.datetime.now()
	html = &quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;It is now %s.&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&quot; % now
	return HttpResponse(html)&lt;/TEXTAREA&gt;&lt;br /&gt;
(이제 필요하다면 이전의 코드(hello 함수)는 생략할 수 있다)&lt;br /&gt;
&lt;br /&gt;views.py으로&amp;nbsp;current_datetime view를 수용하기 위해 만들어진 변경사항을 확인해 보자.&lt;br /&gt;
&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;date 계산을 위해 import datetime을 추가하였다.&lt;/LI&gt;
&lt;LI&gt;새로운 current_datetime 함수는 현재의 시각을 계산한다. 이는 datetime.datetime object를 이용하며, 지역 변수에 값을 저장한다.&lt;/LI&gt;
&lt;LI&gt;python의 &quot;format-string&quot; 기능에 의해 HTML response를 생성하고 있다. %s는 문자열의 위치 지정이 되며, %는 &quot;변수 now의 값으로 %s에 해당되는 문장을 변경하라&quot;라는 뜻이 된다. now 변수는 기술적으로 datetime.datetime object로, string이 아니다. 그러나 %s format은 string 표현으로 변환시키며, &quot;2008-12-13 14:09:39.002731&quot;과 유사하겨 변환한다. 결국 이것으로 인해 HTML string은 &quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;It is noew 2008-12-13 14:09:39.002731.&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&quot;와 같이 결정된다.&lt;/LI&gt;
&lt;LI&gt;마지막으로, view는 HttpResponse object를 리턴하는데, 직접 생성한 response를 전달하였다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;views.py에 추가하였다면, /time/으로 처리하도록 다음과 같이 urls.py을 수정한다.&lt;TEXTAREA style=&quot;WIDTH: 601px; HEIGHT: 119px&quot; class=python rows=5 cols=64 name=code&gt;from django.conf.urls.defaults import *
from mysite.views import hello, current_datetime

urlpatterns = patterns('',
	('^hello/$', hello),	
	('^time/$', current_datetime),
)&lt;/TEXTAREA&gt;&lt;br /&gt;
우리는 이곳에서 두개를 수정하였는데, 처음으로 current_datetime 함수를 import하도록 했다. 두번째가 더 중요한데 /time/ url에 대해 새로운 view를 항당하도록 URLpattern을 추가하였다. 이곳에 아래로 쭉 늘어뜨리면 된다.&lt;br /&gt;
&lt;br /&gt;새로운 view와 수정된 URLconf를 가지고, 테스트하면 아래와 같다.&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile24.uf.tistory.com/original/1306A1444F7A5A83183709&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile24.uf.tistory.com/image/1306A1444F7A5A83183709&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;005.png&quot; height=&quot;86&quot; width=&quot;283&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;&lt;FONT color=#ff8b16&gt;URLconfs와 느슨한 결합(Loose Coupling)&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;이제 URLconf와 일반적인 django의 철학인 &lt;EM&gt;느슨한 결합&lt;/EM&gt;(&lt;EM&gt;loose coupling&lt;/EM&gt;) 원리에 대해 설명할 차례이다. 간단히 설명하자면, loose coupling은 교환 가능한 조각으로 만드는것을 중요한 가치로 삼고 있는 software 개발 방법론이다. 만약 코드가 두개의 loose coupling으로 되어 있다면, 임의의 한개가 수정이 되었을 때, 나머지 한개는 영향이 없거나 거의 없다는 것을 의미한다.&lt;br /&gt;
&lt;br /&gt;django의 URLconf는 그것의 좋은 예이다. django web application에서 url 정의와 view function은 loose coupling되어 있다. 그것은 주어진 view 함수를 위한 url의 결정과 view 함수 자체는 구별된 위치에 정의된다는 것이다. 그로 인해 서로간에 영향을 주지 않도록 하였다.&lt;br /&gt;
&lt;br /&gt;예를 들어, current_datetime view 함수를 보자. 만약 application의 url을 변경해야 한다면(/time/-&amp;gt;/current-time/), view 함수를 생각할 것 없이, URLconf만 얼른 수정하면 된다. 비슷하게, 논리가 변경되어 view 함수를 변경해야 한다면, URL에 영향이 없을 것이다.&lt;br /&gt;
&lt;br /&gt;더 나아가, current-date 함수를 여러개의 URL로 노출하고자 한다면, code의 수정없이 아래와 같이 URLconf만 다루면 된다.&lt;TEXTAREA style=&quot;WIDTH: 606px; HEIGHT: 87px&quot; class=python rows=3 cols=65 name=code&gt;urlpatterns = patterns('',
	('^hello/$', hello),
	('^time/$', current_datetime),
	('^another-time-page/$', current_datetime),
)&lt;/TEXTAREA&gt;&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;세번째 view : Dynamic URLs&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;current_datetime view는 내용(content)이 동적인 경우였다.&amp;nbsp;그러나 URL(/time/)은 여전히 정적이다. 대부분의 web application에서, URL은 page의 output에 영향을 주는 parameter를 내포하고 있다. 예를 들면, 온라인 북스토어 같은 곳에서, 각 책들은 고유의 URL을 가진다고 가정할때, /books/243 그리고 /books/81196/ 등이 될 것이다.&lt;br /&gt;
&lt;br /&gt;이제 시간을 주어진 값으로 조정하는 것을 출력하는 세번째 view를 만들어 보자. /time/plus/1이면 한시간 미래, /time/plus/2이면 두시간 미래의 시간을 출력하는 것을 목표로 하자.&amp;nbsp;초보자라면 아래와 같이 각각의 경우에 대해 다음과 같이 만들지 모른다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 609px; HEIGHT: 127px&quot; class=python rows=4 cols=65 name=code&gt;urlpatterns = patterns('',
	('^time/$', current_datetime),
	('^time/plus/1/$', one_hour_ahead),
	('^time/plus/2/$', two_hours_ahead),
	('^time/plus/3/$', three_hours_ahead),
	('^time/plus/4/$', four_hours_ahead),
)&lt;/TEXTAREA&gt;&lt;br /&gt;
명확하게도 이런 방법은 결함이 있는데, 많은 중복된 view 함수를 야기한다. 그리고, 사전에 정의된 범위의 hour를 지원하는 경우에도 문제가 된다. 만일 미래의 5시간 뒤의 시간을 출려하려면 다시 view를 만들과 URLconf를 수정해야 한다.&lt;br /&gt;
&lt;br /&gt;이러한 조정값(offset)을 처리하기 위해, 어떻게 해야 하는가? 이를 위해서 URLpatterns에 &lt;EM&gt;wildcard&lt;/EM&gt;를 사용할 수 있다. 앞서 설명했듯이 URLpattern은 regular expression인데, &lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;\d+&lt;/SPAN&gt;를 이용하여 일치시키는 경우이다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 606px; HEIGHT: 98px&quot; class=python rows=3 cols=63 name=code&gt;urlpatterns = patterns('',
	# ...	
	(r'^time/plus/\d+/$', hours_ahead),
	# ...
)&lt;/TEXTAREA&gt;&lt;br /&gt;
이러한 새로운 URLpattern은 /time/plus/2/, /time/plus/25/ 혹은 /time/plus/10000000000/를 일치시킨다. 만일 99시간으로 제한한다면, 즉, 1~2개의 숫자로 구성한다면 &lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;\d{1,2}&lt;/SPAN&gt;와 같을 것이다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 598px; HEIGHT: 38px&quot; class=python cols=65 name=code&gt;(r'^time/plus/\d{1,2}/$', hours_ahead),&lt;/TEXTAREA&gt;&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#eaf4cf&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;100%&quot;&gt;web application을 개발할 때는, 모든 기괴한 input data까지 고려해야 한다. 그리고 어떻든지 application에서 해당 input을 지원할지에 대해 결정해야 한다. 일단 우리는 99시간으로 그 설명의 내용을 줄이도록 한다.&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;
우리가 소개했던 중요한 정보중, regular expression가 r 문자로 시작한다는 것이다. 이는 python에게 해당 문자열은 &quot;raw string&quot;으로 간주해라는 것인데, 그것은 backslash(예를 들어, '&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;\n&lt;/SPAN&gt;')를 따로 해석하지 말라라는 뜻이다.&amp;nbsp; 따라서, r'&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;\n&lt;/SPAN&gt;'은 개행을 의미하는 것이 아니라, backslash에 n문자가 결합된 상태이다. 보통 regular expression을 문자열로 전달할 때, backslash가 출돌될 수 있으므로 되도록이면 r 문자로 시작하는 것이 일반적이다. 그래서 이제 부터 모든 URLpattern에 대해서 정의된 regular expression의 문자열은 r로 시작하도록 한다.&lt;br /&gt;
&lt;br /&gt;이제 URL에 대해 wildcard로 지정을 했다면, 그 wildcard data를 전달받는 방법을 알아야 한다. 그래야만 view 함수에서 사용될 offset을 구할수 있기 때문이다. 우리는 이를 위해 URLpattern에서 해당 위치의 값을 괄호로 묶도록 한다. 즉, 와 같이 ...&lt;FONT color=#e31600&gt;&lt;STRONG&gt;(&lt;/STRONG&gt;&lt;/FONT&gt;&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;\&lt;/SPAN&gt;d{1,2}&lt;STRONG&gt;&lt;FONT color=#e31600&gt;)&lt;/FONT&gt;&lt;/STRONG&gt;/$...와 같이 수정한다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 593px; HEIGHT: 38px&quot; class=python cols=64 name=code&gt;(r'^time/plus/(\d{1,2})/$', hours_ahead),
&lt;/TEXTAREA&gt;&lt;br /&gt;
만약 regular expression에 익숙하다면, 아주 편안하게 느껴질 것이다. 이렇게 괄호를 사용하는것은 일치된 text data의 정보를 가져오는데 응용된다.&lt;br /&gt;
&lt;br /&gt;마지막으로 URLconf는 다음과 같은 모습일 것이다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 600px; HEIGHT: 145px&quot; class=python rows=5 cols=64 name=code&gt;from django.conf.urls.defaults import *
from mysite.views import hello, current_datetime, hours_ahead

urlpatterns = patterns('',
    (r'^hello/$', hello),
    (r'^time/$', current_datetime),
    (r'^time/plus/(\d{1,2})/$', hours_ahead),
)&lt;/TEXTAREA&gt;&lt;br /&gt;
이제 hours_ahead view를 만들어 보자.&lt;br /&gt;
&lt;br /&gt;hours_ahead는 current_datetime view와 유사한데, 추가 argument를 받는것이 주요 차이점이다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 608px; HEIGHT: 202px&quot; class=python rows=8 cols=64 name=code&gt;from django.http import Http404, HttpResponse
import datetime

def hours_ahead(request, offset):
	try:
		offset = int(offset)
	except ValueError:
		raise Http404()
	dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
	html = &quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;In %s hour(s), it will be %s.&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&quot; % (offset, dt)
	return HttpResponse(html)&lt;/TEXTAREA&gt;&lt;br /&gt;
이제 code를 검토해 보자.&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;hours_ahead view 함수는 request와 offset 두개의 parameter를 받아들인다.&lt;/LI&gt;
&lt;LI&gt;request는 HttpRequest object이다. 각각의 view는 항상 HttpRequest object를 첫 parameter로 한다.&lt;/LI&gt;
&lt;LI&gt;offset은 URLpattern에 있는 괄호에 해당되는 문자열이 들어온다. 본 예에서는 한개의 괄호가 있었는데, 한개가 더 있는 경우, hours_ahead(request, offset, dummy1)와 같이 추가가 가능하다. 일단 본 예와 같은 경우, /time/plus/3/인 경우 offset은 '3'이 들어온다. 즉, 해당 parameter는 항상 문자열로 이뤄진다.&lt;br /&gt;
&lt;br /&gt;(parameter로 잡힌 문자열은 항상 Unicode object로 이뤄진다. 즉, 일반적인 python bytestring이 아니다. 우선, 여기에서는 크게 신경쓸 필요는 없다)&lt;br /&gt;
&lt;br /&gt;offset 변수는 일반적인 python identifier로 이뤄지면 된다. 단, request parameter뒤에 위치해야 한다.&lt;/LI&gt;
&lt;LI&gt;offset을 가지고 int()를 호출하였다. 이는 문자열을 숫자로 변환한다.&lt;br /&gt;
&lt;br /&gt;만일 'foo'와 같이 변환이 불가한 상황인 경우 ValueError exception이 발생한다. 만일 ValueError가 발생하면 django.http.Http404 exception을 발생하고, 404 &quot;Page not found&quot;를 유발한다.&lt;br /&gt;
&lt;br /&gt;영리한 독자라면 여기서 의문이 발생할 것이다. {&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;\&lt;/SPAN&gt;d(1,2)}를 통해 과연 ValueError 상황이 발생할 것인가? 이다. 그 답은 &quot;아니오&quot;이다. 그 이유는 URLpattern은 input 검증(validation)의 단계에서 동작하는 것으로 제공되기 때문이다. 그런데도 왜 ValueError를 체크하는지 이유는 다음과 같다. view 함수 자체적으로도 이러한 parameter에대한 검증(즉, URLPattern의 regular expression에서의 검증)이 없는 상황을 가정하고 개발하는 것이 좋기 때문이다. loose coupling을 기억하라.&lt;/LI&gt;
&lt;LI&gt;그 다음으로 시각을 계산하는 부분이 나타난다. 새로운건 datetime.timedelta object를 생성하여 시각을 산술하고 그것을 dt 변수에 저장한다. timedelta는 정수를 받아들이기 때문에 int() 함수를 사용하였다.&lt;/LI&gt;
&lt;LI&gt;마지막으로, HTML의 HttpResponse를 전달한다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;이러한 코드를 가지고 테스트하면 아래와 같다.&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile22.uf.tistory.com/original/1504A9414F7AA5BD2C038C&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile22.uf.tistory.com/image/1504A9414F7AA5BD2C038C&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;006.png&quot; height=&quot;70&quot; width=&quot;345&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile1.uf.tistory.com/original/163EA2414F7AA603031ADD&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile1.uf.tistory.com/image/163EA2414F7AA603031ADD&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;007.png&quot; height=&quot;323&quot; width=&quot;507&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile5.uf.tistory.com/original/1175D1444F7AA634014672&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile5.uf.tistory.com/image/1175D1444F7AA634014672&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;008.png&quot; height=&quot;322&quot; width=&quot;513&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
만일, URLpattern에 ...(&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;\&lt;/SPAN&gt;d{1,2})... 를 ...(&lt;SPAN style=&quot;FONT-FAMILY: Arial&quot;&gt;\&lt;/SPAN&gt;d+)...로 변경하면 다음과 같다.&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile22.uf.tistory.com/original/15123D454F7AA6E7280D52&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile22.uf.tistory.com/image/15123D454F7AA6E7280D52&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;009.png&quot; height=&quot;68&quot; width=&quot;339&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile4.uf.tistory.com/original/1879A5474F7AA7432798FF&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile4.uf.tistory.com/image/1879A5474F7AA7432798FF&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;010.png&quot; height=&quot;69&quot; width=&quot;363&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile7.uf.tistory.com/original/207F89474F7AA7901D43F7&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile7.uf.tistory.com/image/207F89474F7AA7901D43F7&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;011.png&quot; height=&quot;308&quot; width=&quot;506&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
그리고, hours_ahead view에서 다음과 같이 input값 검증을 한다면, 다음과 같은 오류가 발생한다.&lt;br /&gt;
즉, 다음은 view 함수에서 raise Http404()에 의한 결과이다.&lt;TEXTAREA style=&quot;WIDTH: 540px; HEIGHT: 239px&quot; class=python rows=7 cols=55 name=code&gt;def hours_ahead(request, offset):
	try:
		offset = int(offset)
	except ValueError:
		raise Http404()

	if (offset &amp;gt; 99):
		raise Http404()
		
	dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
	html = &quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;In %s hour(s), it will be %s.&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&quot; % (offset, dt)
	return HttpResponse(html)&lt;/TEXTAREA&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile2.uf.tistory.com/original/1477764B4F7AA9BF2B37A7&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile2.uf.tistory.com/image/1477764B4F7AA9BF2B37A7&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;012.png&quot; height=&quot;202&quot; width=&quot;508&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;django의 pretty error page&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;이제 views.py에서 python error가 발생시 어떻게 되는지를 설명하고자 한다.&lt;br /&gt;
다음과 같이 offset=int(offset)을 주석처리하여 실행해 보자.&lt;TEXTAREA style=&quot;WIDTH: 561px; HEIGHT: 167px&quot; class=python rows=7 cols=60 name=code&gt;def hours_ahead(request, offset):
	# try:
	#     offset = int(offset)
	# except ValueError:
	#     raise Http404()
	dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
	html = &quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;In %s hour(s), it will be %s.&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&quot; % (offset, dt)
	return HttpResponse(html)&lt;/TEXTAREA&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile7.uf.tistory.com/original/1701F34D4F7AABA4024FC7&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile7.uf.tistory.com/image/1701F34D4F7AABA4024FC7&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;013.png&quot; height=&quot;420&quot; width=&quot;620&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile27.uf.tistory.com/original/20165E444F7B915626519B&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile27.uf.tistory.com/image/20165E444F7B915626519B&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;014.png&quot; height=&quot;456&quot; width=&quot;532&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
즉 /time/plus/3과 같이 접근하면 위와 같은 중요 정보가 포함된 에러 페이지를 볼 수 있는데, &quot;unsupported type for timedelta hours component: unicode&quot;라고 최상단에 TypeRrror 메시지를 포함하고 있다.&lt;br /&gt;
&lt;br /&gt;datetime.timedelta 함수는 hours 파라미터를 integer로 예상하고 있었는데, integer로 변환하는 부분을 주석 처리하였다. 이는 흔히 개발자가 잃으키는 소소한 버그의 한 종류로 설명된다.&lt;br /&gt;
&lt;br /&gt;위 예는 django의 error page를 보여주기 위함이다. 그러면 해당 page가 알려주는 정보에 대해 알아보자.&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;최상단에는 해당 exception에 대한 key 정보(노란색 배경)가 들어있다. exception의 종류, 어떤 parameter가 exception을 잃으켰는지, exception이 발생한 파일, 그리고 line number등이 있다.&lt;/LI&gt;
&lt;LI&gt;key 정보 아래, 해당 exception에 해당되는 python traceback을 보여준다. 이는 python의 command line interpreter에서의 표준 traceback과 유사하다. 물론 좀더 interactive한 화면으로 구성된다. 각 stack상의 level에서 file의 이름, 함수명, line number, 그리고 해당 line의 source code등을 표시한다.&lt;br /&gt;
&lt;br /&gt;각 box(회색) 부분들을 클릭하면 관련 소스 코드와 로컬 변수값등을 체크해 볼 수 있는데, 이는 debugging하는데 큰 도움을 준다&lt;/LI&gt;
&lt;LI&gt;&quot;Switch to copy-and-paste view&quot;를 클릭하면 다른 버전의 traceback을 보여준다. 이는 해당 exception을 다른 technical support에 공유할때 유용하게 사용된다. 예를 들어, django irc chat room이나 django user mail group등이다.&lt;/LI&gt;
&lt;LI&gt;&quot;Request information&quot;은 GET과 POST 정보, cookie 값, CGI header와 같은 meta 정보등을 나열한다.&lt;br /&gt;
그리고 그 아래의 &quot;Settings&quot;를 통해 django 설치에 대한 특정 설정값을 보여준다.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;django error page는 template&amp;nbsp;syntax error같은 특별한 경우 보다 많은 정보를 표시하기도 한다.&lt;br /&gt;
&lt;br /&gt;print 구문을 조심스럽게 이용하여&amp;nbsp;debug에 도움이 되기도한데, 이러한 print 구문없이 django의 error page를 이용할 수도 있다. view의 임의의 위치에 assert False를 추가하면 아래와 같다.&lt;br /&gt;
&lt;TEXTAREA style=&quot;WIDTH: 609px; HEIGHT: 205px&quot; class=python rows=8 cols=64 name=code&gt;def hours_ahead(request, offset):
	try:
		offset = int(offset)
	except ValueError:
		raise Http404()

	assert False
		
	dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
	html = &quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;In %s hour(s), it will be %s.&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&quot; % (offset, dt)
	return HttpResponse(html)&lt;/TEXTAREA&gt;&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile4.uf.tistory.com/original/117C703E4F7B99A81DBAE0&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile4.uf.tistory.com/image/117C703E4F7B99A81DBAE0&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;015.png&quot; height=&quot;222&quot; width=&quot;474&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
마지막으로 이러한 정보는 매우 민감하다. 즉, 공공의 internet 상에서 이런정보가 나타난다는것은 어리석인 일이다. 그래서 이것은 django project가 debug mode일 때에만 나타나도록 하였다. 추후 Chapter 12에서 debug mode를 비활성화하는 방안을 설명한다.&lt;/P&gt;&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-123-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-123-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=27664438&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/123&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/django&quot;&gt;django&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/django/the%20django%20book%20study&quot;&gt;the django book study&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/125&quot; &gt;[05] django의 model&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(1)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/124&quot; &gt;[04] django의 template&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(2)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/123&quot; &gt;[03] django 1.4의 view와 urlconfs&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/04&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/122&quot; &gt;[02] django 1.4 설치와 project 생성하기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/120&quot; &gt;[01] django 소개&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/119&quot; &gt;[00] Chapter 0&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/28&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>the django book study</category>
			<category>django</category>
			<category>urlconf</category>
			<category>View</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/123</guid>
			<comments>http://greenfishblog.tistory.com/123#entry123comment</comments>
			<pubDate>Wed, 04 Apr 2012 10:02:57 +0900</pubDate>
		</item>
		<item>
			<title>[02] django 1.4 설치와 project 생성하기</title>
			<link>http://greenfishblog.tistory.com/122</link>
			<description>&lt;P&gt;원문 : &lt;A href=&quot;http://www.djangobook.com/en/2.0/chapter02/&quot;&gt;http://www.djangobook.com/en/2.0/chapter02/&lt;/A&gt;&amp;nbsp;참고&lt;br /&gt;
&lt;br /&gt;django는 python 2.x (2.3 ~)에서 동작합니다.&lt;br /&gt;
되도록 높은 버전의 python으로 설치하도록 합니다.&lt;br /&gt;
&lt;br /&gt;django는 특히 &lt;A title=&quot;[https://developers.google.com/appengine/docs/python/overview]로 이동합니다.&quot; href=&quot;https://developers.google.com/appengine/docs/python/overview&quot; target=_blank&gt;google app engine&lt;/A&gt;과도 연결되는데, GAE가 안정적으로 지원하는 2.5.x를 사용하도록 합니다.&lt;br /&gt;
&lt;A title=&quot;[http://www.python.org/download/releases/2.5.6/]로 이동합니다.&quot; href=&quot;http://www.python.org/download/releases/2.5.6/&quot; target=_blank&gt;python 2.5.6&lt;/A&gt; 혹은 &lt;A title=&quot;[http://www.python.org/download/releases/2.5.4/]로 이동합니다.&quot; href=&quot;http://www.python.org/download/releases/2.5.4/&quot; target=_blank&gt;2.5.4&lt;/A&gt;를 설치하면 적당하리라 봅니다.&lt;br /&gt;
일단 현재는 2.5.4를 선택하고 진행하도록 하겠습니다.&lt;br /&gt;
물론 되도록 2.5.x 이상으로 해야 기본 sqlite가 설치되어 추가 설치없이 sqlite를 연동할 수 있습니다.&lt;br /&gt;
(sqlite는 그 특징상 daemon 없이 돌 수 있기 때문에, 개발시 상당한 도움을 줍니다.)&lt;br /&gt;
&lt;br /&gt;(django framework 자체가 os 의존성이 없는 것으로 보이므로, 일단 window에서 설치/개발하도록 합니다.&lt;br /&gt;
같은 code를 나중에 linux/unix로 적용해도 문제는 없으리라 봅니다.&lt;br /&gt;
설치와 관련하여, 필요한 경우, linux/unix에 대한 설명도 같이 기술하였습니다.&lt;br /&gt;
물론, django framework에서 os 의존적인 systemcall등은 os와 불리되리라 봅니다.&lt;br /&gt;
허나, django 자체내에서는 그렇진 않아 보입니다.)&lt;br /&gt;
&lt;br /&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile25.uf.tistory.com/original/181959404F7504BF1BE188&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile25.uf.tistory.com/image/181959404F7504BF1BE188&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;001.png&quot; height=&quot;432&quot; width=&quot;499&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
와 같이 C:\python25에 설치합니다.&lt;br /&gt;
&lt;br /&gt;그리고 내컴퓨터-&amp;gt;속성-&amp;gt;고급-&amp;gt;환경 변수를 들어가,&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile25.uf.tistory.com/original/173B59434F7505902F6D74&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile25.uf.tistory.com/image/173B59434F7505902F6D74&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;002.png&quot; height=&quot;400&quot; width=&quot;447&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Path 항목에 &lt;STRONG&gt;;C:\Python25&lt;/STRONG&gt;를 추가합니다.&lt;br /&gt;
&lt;br /&gt;그럼, cmd.exe에서 python을 치면 다음과 같이 실행됩니다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;C:\&amp;gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python&lt;br /&gt;
&lt;/STRONG&gt;&lt;/FONT&gt;Python 2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel)] on&lt;br /&gt;
win32&lt;br /&gt;
Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;
그다음 django를 설치합니다.&lt;br /&gt;
현재 가장 최신의 official 버전은 1.4로, &lt;A title=&quot;[https://www.djangoproject.com/download/]로 이동합니다.&quot; href=&quot;https://www.djangoproject.com/download/&quot; target=_blank&gt;이곳&lt;/A&gt;을 통해 다운로드 합니다.&lt;br /&gt;
tar와 gz를 &lt;A title=&quot;[http://www.7-zip.org/download.html]로 이동합니다.&quot; href=&quot;http://www.7-zip.org/download.html&quot; target=_blank&gt;7zip&lt;/A&gt;등으로 풀어서 C:\Django-1.4에 복사합니다.&lt;br /&gt;
&lt;br /&gt;그리고, cmd.exe에서,&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\&amp;gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;cd&lt;/FONT&gt;&lt;/STRONG&gt; Django-1.4&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\Django-1.4&amp;gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;와 같이 해당 경로로 들어갑니다.&lt;br /&gt;
&lt;br /&gt;그리고, &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;python setup.py install&lt;/STRONG&gt;&lt;/FONT&gt; 하면 설치가 진행됩니다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;...&lt;br /&gt;
copying django\contrib\sites\locale\zh_TW\LC_MESSAGES\django.po -&amp;gt; C:\Python25\L&lt;br /&gt;
ib\site-packages\django\contrib\sites\locale\zh_TW\LC_MESSAGES&lt;br /&gt;
running install_egg_info&lt;br /&gt;
Writing C:\Python25\Lib\site-packages\Django-1.4-py2.5.egg-info&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\Django-1.4&amp;gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;
여기까지 왔다면 C:\Django-1.4는 더이상 필요없으니 삭제해도 됩니다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;C:\&amp;gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;python&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
Python 2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel)] on&lt;br /&gt;
win32&lt;br /&gt;
Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;import django&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;django.VERSION&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
(1, 4, 0, 'final', 0)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;와 같이 django 1.4가 설치됨을 확인할 수 있습니다.&lt;br /&gt;
&lt;br /&gt;참고로 설치후 C:\Python25 경로의 크기가 약 27.8MB 정도 늘어납니다.&lt;br /&gt;
&lt;br /&gt;이제 django project를 만들어 보도록 합니다.&lt;br /&gt;
&lt;br /&gt;아래 부분은 linux/unix server에서 적용할때 해당되는 내용으로 참고하시기 바랍니다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#e8e8e8&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #dadada 1px solid; BORDER-LEFT: #dadada 1px solid; BORDER-TOP: #dadada 1px solid; BORDER-RIGHT: #dadada 1px solid&quot; width=&quot;100%&quot;&gt;django는 자체 웹서버를 가동시킬 수 있습니다. 물론 -개발용-입니다.&lt;br /&gt;
그래서 개발 이후 deploy할때등은 web server(apache나 ngnix등...)로 연동하게 됩니다.&lt;br /&gt;
&lt;br /&gt;보통 /var/www와 같은 http root document directory에 php 소스 코드등이 들어가게 되는데,&lt;br /&gt;
django는 특징상 해당 directory 밖에 있어도 가능합니다. 물론 내부에 있어도 무방하나,&lt;br /&gt;
굳이 django의 source 코드까지 외부에 노출할 필요가 없기 때문에,&lt;br /&gt;
예를 들어 /home/webuser/djangoroot 와 같이 임의의 계정 하부로 두는 것을 보안상 추천합니다.&amp;nbsp;&lt;br /&gt;
&lt;br /&gt;만일 django-admin.py startproject 했을때 &quot;permission denied&quot;가 발생했다면,&lt;br /&gt;
django-admin.py가 있는 경로(예, /usr/local/bin)에 들어가 chmod +x django-admin.py 하시기 바랍니다.&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\&amp;gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;mkdir mydjango&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\&amp;gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;cd mydjango&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\mydjango&amp;gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;django-admin.py startproject mysite&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
'django-admin.py'은(는) 내부 또는 외부 명령, 실행할 수 있는 프로그램, 또는&lt;br /&gt;
배치 파일이 아닙니다.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\mydjango&amp;gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;와 같이 django-admin.py가 동작하지 않습니다.&lt;br /&gt;
&lt;br /&gt;이때는, &lt;STRONG&gt;;C:\Python25\Lib\site-packages\django\bin&lt;/STRONG&gt;경로를 Path에 추가하면 됩니다.&amp;nbsp;&lt;br /&gt;
그럼 아래와 같이 됩니다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\&amp;gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;cd mydjango&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\mydjango&amp;gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;django-admin.py startproject mysite&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\mydjango&amp;gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;와 같이 성공되며,&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile23.uf.tistory.com/original/11653B494F7510C71E8B68&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile23.uf.tistory.com/image/11653B494F7510C71E8B68&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;004.png&quot; height=&quot;102&quot; width=&quot;230&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile3.uf.tistory.com/original/1372304B4F750F691461BC&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile3.uf.tistory.com/image/1372304B4F750F691461BC&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;003.png&quot; height=&quot;150&quot; width=&quot;270&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
와 같이 __init__.py / manage.py / settings.py / urls.py / wsgi.py 와 같이 5개의 python 파일이 생성됩니다.&lt;br /&gt;
&lt;br /&gt;만일 linux/unix환경이라면,&lt;br /&gt;
&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;sudo &lt;/FONT&gt;&lt;/STRONG&gt;ln -s /......./djagno-admin.py &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;/usr/local/bin/django-admin.py&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
와 같이 django-admin.py 경로에 대한 simbolic link로 해결할 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;C:\mydjango\mysite&amp;gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;python manage.py runserver&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
Validating models...&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ffffff&gt;0 errors found&lt;br /&gt;
Django version 1.4, using settings 'mysite.settings'&lt;br /&gt;
Development server is running at &lt;/FONT&gt;&lt;A href=&quot;http://127.0.0.1:8000/&quot;&gt;&lt;FONT color=#ffffff&gt;http://127.0.0.1:8000/&lt;/FONT&gt;&lt;/A&gt;&lt;br /&gt;
&lt;FONT color=#ffffff&gt;Quit the server with CTRL-BREAK.&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;와 같이 django 웹서버로 테스트 할 수 있습니다.&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile25.uf.tistory.com/original/1162F7494F751217213CC7&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile25.uf.tistory.com/image/1162F7494F751217213CC7&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;005.png&quot; height=&quot;300&quot; width=&quot;573&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
와 같이 웹브라우징을 통해 테스트할 수 있습니다.&lt;br /&gt;
&lt;br /&gt;이러한 django의 내장 웹서버는, 관련 소스 코드가 수정되면 자동으로 reload하게 되므로,&lt;br /&gt;
개발시 큰 도움을 주게 됩니다.&lt;/P&gt;&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-122-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-122-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=27481107&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/122&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/django&quot;&gt;django&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/django/the%20django%20book%20study&quot;&gt;the django book study&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/125&quot; &gt;[05] django의 model&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(1)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/124&quot; &gt;[04] django의 template&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(2)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/123&quot; &gt;[03] django 1.4의 view와 urlconfs&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/04&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/122&quot; &gt;[02] django 1.4 설치와 project 생성하기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/120&quot; &gt;[01] django 소개&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/119&quot; &gt;[00] Chapter 0&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/28&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>the django book study</category>
			<category>django</category>
			<category>Python</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/122</guid>
			<comments>http://greenfishblog.tistory.com/122#entry122comment</comments>
			<pubDate>Fri, 30 Mar 2012 10:56:35 +0900</pubDate>
		</item>
		<item>
			<title>[01] django 소개</title>
			<link>http://greenfishblog.tistory.com/120</link>
			<description>&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;원문 : &lt;A href=&quot;http://www.djangobook.com/en/2.0/chapter01/&quot;&gt;http://www.djangobook.com/en/2.0/chapter01/&lt;/A&gt; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;이 책은 시간을 절약하면서 즐겁게 web을 개발 할 수 있는 web development framework인 django에 대해 다룬다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;django를 사용하면 high-quality web 개발이 가능하다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;web 개발을, 좋게 얘기하자면 exciting하고 creative한 활동인데 반해, &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;나쁘게 얘기하자면, 반복적이고 성가시고 좌절감을 안겨준다고 할 수 있다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;django는 당신에게 재이있는 요소에 집중하도록 해주는데, &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;그것은 공통의 web 개발 pattern의 추상화, 빈번한 programming 작업에 대한 지름길(shortcut), 그리고 &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;문제 해결을 위한 규약을 제공한다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;django는 필요시 framework 범위 밖의 작업도 가능케 하면서, 당신의 방법에 대해 관여하지 않는다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;본 책의 목표는 당신을 django의 전문가로 만들기 위함이다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;그 촛점은 두개로 나눠지는데, &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;첫째는 깊이있는 설명 즉, django는 무엇이며 어떻게 web application을 빌드하는지를 다루며, &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;부번째로는 &quot;내 project에 이런 도구를 어떻게 적용할까?&quot;에 대한 답을 구해주기 위한 &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;고수준의 concept을 설명한다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;본 책을 읽음으로 유지보수하는데 깔끔하고 쉬운 코드로 구성된 web site를 &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;보다 빠르게 개발하는 skill을 배울 수 있다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림&quot;&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;web framework은 무엇인가?&lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt; &lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;django는 새로운 web framework의 주요 멤버인데, 그럼 web framework 용어의 뜻은 무었인가? &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;그 답을 찾기위해 framework 없이 python으로 씌어진 web application의 design을 고려해 보자. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;본 책을 통해 우리는 지름길 없이 작업을 완료할 수 있는 기본적인 방법은 제공해 줄 것인데, &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;그 지름길이 매우 도움이 된다는 것을 인지시켜주기 위해서이다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;(또한 지름길없이 완료하는 방법을 알아야 하는것이 중요한데, 지름길이 언제나 유용하건 아니기 때문이다) &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;python web app을 빌드하기 위한 대부분의 방법은 Common Gateway Interface(CGI) 표준을 사용하는 것이다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;HTML을 output하는 python script를 만든뒤 확장자를 &quot;.cgi&quot; 확장자로 web server에 저장하고 web browser로 &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;방문한다. 그것이 다다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;아래는 python cgi script 예인데, db로 부터 출판된 책중 최근의 10개를 출력하는 것이다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;문법은 그다지 신경쓰지 말고, 어떻게 이뤄지는지 느끼기 바란다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;DIV&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse; BACKGROUND: #d6e3bc&quot; border=0&gt;
&lt;COLGROUP&gt;
&lt;COL style=&quot;WIDTH: 637px&quot;&gt;&lt;/COLGROUP&gt;
&lt;TBODY vAlign=top&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: 0.5pt solid; BORDER-LEFT: 0.5pt solid; PADDING-LEFT: 7px; PADDING-RIGHT: 7px; BORDER-TOP: 0.5pt solid; BORDER-RIGHT: 0.5pt solid&quot;&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;#!/usr/bin/env python &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;import MySQLdb &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;print &quot;Content-Type: text/html\n&quot; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;print &quot;&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;Books&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&quot; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;print &quot;&amp;lt;body&amp;gt;&quot; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;print &quot;&amp;lt;h1&amp;gt;Books&amp;lt;/h1&amp;gt;&quot; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;print &quot;&amp;lt;ul&amp;gt;&quot; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;connection = MySQLdb.connect(user='me', passwd='letmein', db='my_db') &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;cursor = connection.cursor() &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;cursor.execute(&quot;SELECT name FROM books ORDER BY pub_date DESC LIMIT 10&quot;) &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;for row in cursor.fetchall(): &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;print &quot;&amp;lt;li&amp;gt;%s&amp;lt;/li&amp;gt;&quot; % row[0] &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;print &quot;&amp;lt;/ul&amp;gt;&quot; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;print &quot;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&quot; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;connection.close()&lt;/SPAN&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;우선 CGI의 요구사항을 만족하기 위해 &quot;Content-Type&quot;을 출력하고 개행한다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;다음으로 html 서두부분을 출력하고 db 연결한뒤 최근 10개의 책 이름을 구하기 위해 query를 실행한다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;해당 책에 대해 loop 돌면서 책 이름을 생성한다. 마지막으로 html을 종료하고, db를 닫는다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;이것과 비슷한 단한번 사용될 page를 만든다고 할때, 처음부터 쓰기 접근법(write-it-from-scratch)은 나쁘진 않다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;위 코드는 이해하는데 충분히 단순하고, 심지어 초보 개발자라 하더라도 시작부터 종료까지 16줄의 python 코드를 &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;읽을 수 있을 것이다. 더이상 따로 배울건 없으며, 읽을 다른이도 없을 것이다. 또한 배포(deploy)도, &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;&quot;.cgi&quot;로 끝내고 web server로 upload하기 때문에 쉽다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;이러한 단순함에도 불구하고 이러한 접근방법은 많은 문제를 야기한다. 다음 질문에 대한 답변을 만들어 보라. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;- application의 많은 부분이 db에 접근이 필요할 때 무엇이 발생하는가? &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;확실하게는 db 접속 code는 개별 cgi script에 복사될 필요가 없다. 공유된 함수 사용하는 것으로 개선해야 한다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;- 개발자가 &quot;Content-Type&quot;과 db 닫기에 대해 정말 걱정해야 하는가? &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;이런것은 개발자의 생산성을 줄이고 실수를 유발할 수 있다. 이러한 처리는 몇개의 공통 infrastructure를 통해 &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;처리하는것이 최선일 것이다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;- 이 코드가 다양한 환경에서 재사용된다면, 각각의 db와 password는 어떻게 구별되는가? &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;이 싯점에서는 몇몇 환경별 지정 가능한 설정이 필요하다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;- python 코드에 대한 경험이 없는 web designer가 해당 page에 대해 redesign을 한다면, 어떤일이 발생하겠는가? &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;하나라도 잘못된 문자가 포함된다면 전체 application은 crash될 것이다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;이상적으로, page의 로직(db로 부터의 책 제목들)은 html display로 부터 개별 분리되어야 하고, &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;그렇다면 designer는 전자에 영향없이 후자만 개발하면 된다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;web framework는 이러한 문제를 해결하기 위한 의도로 작성되었다. web framework은 &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;application을 위해 programming infrastructure를 제공하고 개발자로 하여금 깔끔하고 유지보수 쉬운 코드를 &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;재개발 없이 가능케 한다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림&quot;&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 14pt&quot;&gt;the MVC Design Pattern&lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt; &lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;이제 앞의 접근법과 web framework 접근법의 차이를 보여주기 위해, 앞선 cgi code를 django로 한 것을 &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;나타낸다. 단, 4개 이상의 python 파일(models.py, view.py, urls.py)과 html template 파일(latest_books.html)로 &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;나눠서 표기한다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;DIV&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse; BACKGROUND: #d6e3bc&quot; border=0&gt;
&lt;COLGROUP&gt;
&lt;COL style=&quot;WIDTH: 637px&quot;&gt;&lt;/COLGROUP&gt;
&lt;TBODY vAlign=top&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: 0.5pt solid; BORDER-LEFT: 0.5pt solid; PADDING-LEFT: 7px; PADDING-RIGHT: 7px; BORDER-TOP: 0.5pt solid; BORDER-RIGHT: 0.5pt solid&quot;&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;# models.py (the database tables) &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;from django.db import models &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;class Book(models.Model): &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name = models.CharField(max_length=50) &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pub_date = models.DateField() &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;# views.py (the business logic) &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;from django.shortcuts import render_to_response &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;from models import Book &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;def latest_books(request): &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;book_list = Book.objects.order_by('-pub_date')[:10] &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return render_to_response('latest_books.html', {'book_list': book_list}) &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;# urls.py (the URL configuration) &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;from django.conf.urls.defaults import * &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;import views &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;urlpatterns = patterns('', &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(r'^latest/$', views.latest_books), &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;) &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;# latest_books.html (the template) &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;Books&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;&amp;lt;body&amp;gt; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;&amp;lt;h1&amp;gt;Books&amp;lt;/h1&amp;gt; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;&amp;lt;ul&amp;gt; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;{% for book in book_list %} &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;&amp;lt;li&amp;gt;{{ book.name }}&amp;lt;/li&amp;gt; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;{% endfor %} &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;&amp;lt;/ul&amp;gt; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;역시 syntax는 크게 걱정하지 말고, 전체 design을 보고 느껴보기 바란다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;- models.py은 db table의 description을 포함하는데, python의 class로 표현된다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;이것을 model이라고 한다. 그것을 사용하여 sql없이 db의 crud(create,retreive, update, delete)를 사용할 수 있다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;- views.py는 해당 page에 대해 business logic을 수행한다. latest_books() 함수는 view라고 읽혀진다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;- urls.py는 주어진 URL pattern으로 어떤 view를 지정할지를 결정한다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;위 코드는 /latest/ URL은 latest_books() 함수에 의해 처리되록 한다. 만약 example.com과 같은 domain이라면, &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;어떠한 http://example.com/latest/는 latest_books() 함수를 실행토록 한다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;- latest_books.html은 해당 page의 design에 해당되는 html template를 결정한다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;basic logic statement로 구성된 template 언어를 사용한다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;이러한 항목들은 Model-View-Controller(MVC)로 불려진 pattern을 느슨하게 따르고 있다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;MVC는 data 정의와 접근에 대한 코드(model)은 &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;request-routing 논리(controller)와 분리되어 실행되고, &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;분리된 UI(view)를 가진다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;(자세한 MVC 모델은 Chapter 5.에서 설명한다.) &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;이러한 접근방법의 가장큰 장점중 하나는 각 compoent는 느슨하게 연결되어 있다는 것이다. (loosely coupled) &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;django의 각 구별된 조각은 단일 목적이며 다른 조각에 영향을 미치지 않는다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;예를 들어, 개발자는 URL 변경을 일부분만 수정하고, 이는 다른 코드들의 영향을 미치지 않는다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;designer는 python code를 손대지 않는다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;db 관리자는 db table 이름을 변경할 수 있는데, 이는 단일 위치의 코드만 수정하면 된다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;즉, 전체 file들을 찾아 변경할 필요가 없다는 뜻이다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;본 책에서는 MVC의 각 component는 그들만의 chapter가 존재한다. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-FAMILY: 굴림; FONT-SIZE: 9pt&quot;&gt;chapter 3은 view, chapter 4는 templete, 그리고 chapter 5는 model이다. &lt;/SPAN&gt;&lt;/P&gt;&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=27403516&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/120&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/django&quot;&gt;django&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/django/the%20django%20book%20study&quot;&gt;the django book study&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/125&quot; &gt;[05] django의 model&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(1)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/124&quot; &gt;[04] django의 template&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(2)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/123&quot; &gt;[03] django 1.4의 view와 urlconfs&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/04&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/122&quot; &gt;[02] django 1.4 설치와 project 생성하기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/120&quot; &gt;[01] django 소개&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/119&quot; &gt;[00] Chapter 0&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/28&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>the django book study</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/120</guid>
			<comments>http://greenfishblog.tistory.com/120#entry120comment</comments>
			<pubDate>Wed, 28 Mar 2012 16:38:04 +0900</pubDate>
		</item>
		<item>
			<title>프로세스 생성 종결자 (ShellExecute / CreateProcess)</title>
			<link>http://greenfishblog.tistory.com/118</link>
			<description>&lt;P&gt;Vista 이상에서 되도록 ShellExecute를 권장하고 있습니다.&lt;br /&gt;
그래서 ShellExecute를 그냥 사용하게 되는데,&lt;br /&gt;
간혹 Shell 쪽의 COM이 깨져 ShellExecute가 실패하는 경우가 있습니다.&lt;br /&gt;
그때는 CreateProcess를 해줘야 합니다.&lt;br /&gt;
&lt;br /&gt;ShellExecute / CreateProcess 모두 많은 Argument가 있어 사용하기 복잡합니다.&lt;br /&gt;
그래서,&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;실행 경로 (lpszExePath)&lt;/LI&gt;
&lt;LI&gt;종료때 까지 기다릴지 여부 (bBlock)&lt;/LI&gt;
&lt;LI&gt;Exit Code (pnExitCode, Optional)&lt;/LI&gt;
&lt;LI&gt;실행 파라미터 (lpszParam, Optional)&lt;/LI&gt;
&lt;LI&gt;실행 프로세스의 Current Directory (lpszDirectory, Optional)&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;와 같이 실제 자주 사용되는 Argument로 종합한 함수를 공유합니다.&lt;br /&gt;
물론, Optional은 NULL이나 0을 전달해도 무방합니다.&lt;br /&gt;
&lt;br /&gt;내부에서 ShellExecute가 실패하면 CreateProcess로 연결되니, 걱정않으셔도 됩니다. :)&lt;/P&gt;&lt;TEXTAREA class=c++ name=code&gt;// TRACELOG는 TRACE로그를 찍는 것일 수 있음
// 각자 정의한 것으로 Replace 요망
// 삭제 가능

// Block이 TRUE이고 ERROR_SUCCESS 리턴일때 pnExitCode 의미 있음
DWORD ExecuteProcess(IN LPCTSTR lpszExePath, IN BOOL bBlock, OPTIONAL OUT PINT pnExitcode, OPTIONAL IN LPCTSTR lpszParam, OPTIONAL IN LPCTSTR lpszDirectory)
{
	DWORD				dwRtnValue		= ERROR_SUCCESS;
	DWORD				dwResult		= 0;
	SHELLEXECUTEINFO	stInfo			= {0,};
	HANDLE				hCreateProcess	= NULL;
	STARTUPINFO			si				= {0,};
	PROCESS_INFORMATION pi				= {0,};
	LPTSTR				lpszCmd			= {0,};
	CString				strCmdLine;

	if (NULL != pnExitcode)
	{
		(*pnExitcode) = -1;
	}

	if (NULL == lpszExePath)
	{
		dwRtnValue = ERROR_INVALID_PARAMETER;
		goto FINAL;
	}

	TRACELOG(TEXT(&quot;[INFO] ExecuteCalled&quot;));
	TRACELOG(TEXT(&quot;[INFO] lpszExePath : %s&quot;), lpszExePath);
	if (NULL != lpszParam)
	{
		TRACELOG(TEXT(&quot;[INFO] lpszParam : %s&quot;), lpszParam);
	}
	if (NULL != lpszDirectory)
	{
		TRACELOG(TEXT(&quot;[INFO] lpszDirectory : %s&quot;), lpszDirectory);
	}
	TRACELOG(TEXT(&quot;[INFO] Block : %d&quot;), bBlock);

	stInfo.cbSize		= sizeof(stInfo);
	stInfo.lpFile		= lpszExePath;
	stInfo.lpDirectory	= lpszDirectory;
	stInfo.lpParameters	= lpszParam;
	stInfo.fMask		= SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;
	stInfo.nShow		= SW_SHOW;

	if (FALSE == ::ShellExecuteEx(&amp;amp;stInfo))
	{
		// ShellExcute가 실패했다.
		TRACELOG(TEXT(&quot;[ERROR] Fail to ShellExecuteEx, %d&quot;), ::GetLastError());

		// CreateProcess로 재도전
		strCmdLine = lpszExePath;
		strCmdLine.TrimRight(TEXT(&quot;\&quot;&quot;));
		strCmdLine.TrimLeft (TEXT(&quot;\&quot;&quot;));
		strCmdLine.Insert(0, TEXT(&quot;\&quot;&quot;));
		strCmdLine += TEXT(&quot;\&quot;&quot;);

		si.cb = sizeof(si);

		if (NULL != lpszParam)
		{
			strCmdLine += TEXT(&quot; &quot;);
			strCmdLine += lpszParam;
		}

		lpszCmd = new TCHAR[_tcslen(strCmdLine)+1];
		if (NULL == lpszCmd)
		{
			dwRtnValue = ERROR_NOT_ENOUGH_MEMORY;
			goto FINAL;
		}
		ZeroMemory(lpszCmd, sizeof(TCHAR)*(_tcslen(strCmdLine)+1));
		::StringCchCopy(lpszCmd, _tcslen(strCmdLine)+1, strCmdLine);
		strCmdLine.Empty();
		if (FALSE == ::CreateProcess(NULL, 
									 lpszCmd, 
									 NULL, 
									 NULL, 
									 FALSE, 
									 0, 
									 NULL, 
									 lpszDirectory, 
									 &amp;amp;si,
									 &amp;amp;pi))
		{
			dwRtnValue = ::GetLastError();
			TRACELOG(TEXT(&quot;[INFO] Fail to CreateProcess, %d&quot;), dwRtnValue);
			goto FINAL;
		}

		if (TRUE == bBlock)
		{
			TRACELOG(TEXT(&quot;[INFO] Try to Wait process(CP) %s&quot;), lpszExePath);
			dwRtnValue = ::WaitForSingleObject(pi.hProcess, INFINITE);
			TRACELOG(TEXT(&quot;[INFO] Finished to Wait process(CP) %s&quot;), lpszExePath);

			if (NULL != pnExitcode)
			{
				if (FALSE == ::GetExitCodeProcess(pi.hProcess, (DWORD*)pnExitcode))
				{
					dwRtnValue = ::GetLastError();
					TRACELOG(TEXT(&quot;[ERROR] Fail to GetExitCode(CP), GetLastError=%d&quot;), dwRtnValue);
					goto FINAL;
				}

				TRACELOG(TEXT(&quot;[INFO] ExitCode(CP)=%d&quot;), (*pnExitcode));
			}
		}

		if (NULL != pi.hProcess)
		{
			::CloseHandle(pi.hProcess);
			pi.hProcess = NULL;
		}

		if (NULL != pi.hThread)
		{
			::CloseHandle(pi.hThread);
			pi.hThread = NULL;
		}
	}
	else
	{
		if (NULL != stInfo.hProcess)
		{
			if (TRUE == bBlock)
			{
				TRACELOG(TEXT(&quot;[INFO] Try to Wait process %s&quot;), lpszExePath);
				dwResult = ::WaitForSingleObject(stInfo.hProcess, INFINITE);
				TRACELOG(TEXT(&quot;[INFO] Finished to Wait process %s&quot;), lpszExePath);

				if (NULL != pnExitcode)
				{
					if (FALSE == ::GetExitCodeProcess(stInfo.hProcess, (DWORD*)pnExitcode))
					{
						dwRtnValue = ::GetLastError();
						TRACELOG(TEXT(&quot;[ERROR] Fail to GetExitCode, GetLastError=%d&quot;), dwRtnValue);
						goto FINAL;
					}

					TRACELOG(TEXT(&quot;[INFO] ExitCode=%d&quot;), (*pnExitcode));
				}
			}

			::CloseHandle(stInfo.hProcess);
			stInfo.hProcess = NULL;
		}
	}

	dwRtnValue = ERROR_SUCCESS;

FINAL:
	if (NULL == lpszCmd)
	{
		delete [] lpszCmd;
		lpszCmd = NULL;
	}

	if (NULL != stInfo.hProcess)
	{
		::CloseHandle(stInfo.hProcess);
		stInfo.hProcess = NULL;
	}
	if (NULL != pi.hProcess)
	{
		::CloseHandle(pi.hProcess);
		pi.hProcess = NULL;
	}

	if (NULL != pi.hThread)
	{
		::CloseHandle(pi.hThread);
		pi.hThread = NULL;
	}
	return dwRtnValue;
}
&lt;SPAN id=tx_marker_caret&gt;&lt;/SPAN&gt;&lt;/TEXTAREA&gt;&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-118-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-118-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=27214758&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/118&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/프로그래밍&quot;&gt;프로그래밍&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/프로그래밍/Let%27s%20Share%20it&quot;&gt;Let's Share it&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/127&quot; &gt;PE 포맷 바이너리 파일의 버전을 구하는 함수&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/118&quot; &gt;프로세스 생성 종결자 (ShellExecute / CreateProcess)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/117&quot; &gt;손쉽게 File을 나열할 수 있는 class 공유(FindFirstFile/FindNextFile Wrapper)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/116&quot; &gt;VC9.0에서 crypto++ library를 이용하여 SHA256(sha2) 구하기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/12/14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/115&quot; &gt;비동기(OVERLAPPED I/O, IOCP, Thread Pool) IPC PIPE Class 공유&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/12/14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/114&quot; &gt;[ATL/MFC/C++] Ini Parser(ini 파서)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/11/30&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>Let's Share it</category>
			<category>CreateProcess</category>
			<category>ShellExecute</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/118</guid>
			<comments>http://greenfishblog.tistory.com/118#entry118comment</comments>
			<pubDate>Fri, 23 Mar 2012 14:50:29 +0900</pubDate>
		</item>
		<item>
			<title>손쉽게 File을 나열할 수 있는 class 공유(FindFirstFile/FindNextFile Wrapper)</title>
			<link>http://greenfishblog.tistory.com/117</link>
			<description>&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock center&quot; style=&quot;text-align: center; clear: both;&quot;&gt;&lt;a href=&quot;http://greenfishblog.tistory.com/attachment/cfile3.uf@1303CA334F6BDEE719BE7E.cpp&quot;&gt;&lt;img src=&quot;http://i1.daumcdn.net/cfs.tistory/v/110706133414/blog/image/extension/unknown.gif&quot; alt=&quot;&quot; style=&quot;vertical-align: middle;&quot; /&gt; FileTraverse.cpp&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock center&quot; style=&quot;text-align: center; clear: both;&quot;&gt;&lt;a href=&quot;http://greenfishblog.tistory.com/attachment/cfile1.uf@137773334F6BDEE723E899.h&quot;&gt;&lt;img src=&quot;http://i1.daumcdn.net/cfs.tistory/v/110706133414/blog/image/extension/unknown.gif&quot; alt=&quot;&quot; style=&quot;vertical-align: middle;&quot; /&gt; FileTraverse.h&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
파일 나열을 위해 FindFirstFile / FindNextFile을 사용하는데,&lt;br /&gt;
보통 SubDirectory를 지원하기 위해선 재귀호출을 사용해야 합니다.&lt;br /&gt;
그러다보면 자연히 코드가 좀더 너저분해 지는 경향이 있습니다.&lt;br /&gt;
그리고, Path의 Component(즉, \...\ 사이에 있는 길이)가 MAX_PATH를 넘어가면 발생하는 문제 해결을 위해,&lt;br /&gt;
Naming a file(&lt;A href=&quot;file:///?\&quot;&gt;\\?\&lt;/A&gt;를 붙이기)이 필요합니다. 해당 부분도 역시 지원합니다.&lt;br /&gt;
&lt;br /&gt;다음 code(class)만 추가하면 됩니다.&lt;br /&gt;
&lt;/P&gt;&lt;TEXTAREA class=c++ name=code&gt;#pragma once
#include &quot;FileTraverse.h&quot;

class CFileEnumProcess : public CFileTraverse
{
public:
	CFileEnumProcess(void);
	~CFileEnumProcess(void);

public:
	virtual BOOL OnTraverse(IN LPCTSTR lpszFullPath, IN LPCTSTR lpszNamedPath, IN PWIN32_FIND_DATA pstFD);
};
&lt;/TEXTAREA&gt; &lt;br /&gt;
&lt;br /&gt;&lt;TEXTAREA class=c++ name=code&gt;#include &quot;StdAfx.h&quot;
#include &quot;FileEnumProcess.h&quot;

CFileEnumProcess::CFileEnumProcess(void)
{
}

CFileEnumProcess::~CFileEnumProcess(void)
{
}

BOOL CFileEnumProcess::OnTraverse(IN LPCTSTR lpszFullPath, IN LPCTSTR lpszNamedPath, IN PWIN32_FIND_DATA pstFD)
{
	BOOL bContinue = TRUE;

	_tprintf(TEXT(&quot;[0x%x] %s\r\n&quot;), pstFD-&amp;gt;dwFileAttributes, lpszFullPath);

	return bContinue;
}
&lt;/TEXTAREA&gt;&lt;br /&gt;
&lt;br /&gt;즉, CFileTraverse를 상속하고,&lt;br /&gt;
virtual BOOL &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;OnTraverse&lt;/STRONG&gt;&lt;/FONT&gt;(IN LPCTSTR lpszFullPath, IN LPCTSTR lpszNamedPath, IN PWIN32_FIND_DATA pstFD);&lt;br /&gt;
만 재정의 하시면 됩니다.&lt;br /&gt;
&lt;br /&gt;Enum을 중단하려면 FALSE를 리턴하면 됩니다.&lt;br /&gt;
&lt;br /&gt;위와 같이 class를 정의하고,&lt;br /&gt;
&lt;TEXTAREA class=c++ name=code&gt;#include &quot;stdafx.h&quot;

#include &quot;FileEnumProcess.h&quot;

int _tmain(int argc, _TCHAR* argv[])
{
	CFileEnumProcess cFileEnum;

	cFileEnum.Traverse(TEXT(&quot;C:\\&quot;), TRUE);
}
&lt;/TEXTAREA&gt;&lt;br /&gt;
와 같이 호출하면, C:\ 하부에 있는 파일을 아래와 같이 나열(_tprintf)합니다.&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;...&lt;br /&gt;
[0x20] C:\eclipse\configuration\org.eclipse.osgi\bundles\321\1\.cp\icons\full\dl&lt;br /&gt;
cl16\localtypes_co.gif&lt;br /&gt;
[0x20] C:\eclipse\configuration\org.eclipse.osgi\bundles\321\1\.cp\icons\full\dl&lt;br /&gt;
cl16\public_co.gif&lt;br /&gt;
[0x20] C:\eclipse\configuration\org.eclipse.osgi\bundles\321\1\.cp\icons\full\dl&lt;br /&gt;
cl16\static_co.gif&lt;br /&gt;
[0x10] C:\eclipse\configuration\org.eclipse.osgi\bundles\321\1\.cp\icons\full\dt&lt;br /&gt;
ool16&lt;br /&gt;
[0x20] C:\eclipse\configuration\org.eclipse.osgi\bundles\321\1\.cp\icons\full\dt&lt;br /&gt;
ool16\mark_occurrences.gif&lt;br /&gt;
...&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-117-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-117-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=27210044&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/117&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/프로그래밍&quot;&gt;프로그래밍&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/프로그래밍/Let%27s%20Share%20it&quot;&gt;Let's Share it&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/127&quot; &gt;PE 포맷 바이너리 파일의 버전을 구하는 함수&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/04/30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/118&quot; &gt;프로세스 생성 종결자 (ShellExecute / CreateProcess)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/117&quot; &gt;손쉽게 File을 나열할 수 있는 class 공유(FindFirstFile/FindNextFile Wrapper)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/116&quot; &gt;VC9.0에서 crypto++ library를 이용하여 SHA256(sha2) 구하기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/12/14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/115&quot; &gt;비동기(OVERLAPPED I/O, IOCP, Thread Pool) IPC PIPE Class 공유&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/12/14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/114&quot; &gt;[ATL/MFC/C++] Ini Parser(ini 파서)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/11/30&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>Let's Share it</category>
			<category>FindFirstFile</category>
			<category>FindNextFile</category>
			<category>Recurse</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/117</guid>
			<comments>http://greenfishblog.tistory.com/117#entry117comment</comments>
			<pubDate>Fri, 23 Mar 2012 13:06:13 +0900</pubDate>
		</item>
		<item>
			<title>VC9.0에서 crypto++ library를 이용하여 SHA256(sha2) 구하기</title>
			<link>http://greenfishblog.tistory.com/116</link>
			<description>&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock center&quot; style=&quot;text-align: center; clear: both;&quot;&gt;&lt;a href=&quot;http://greenfishblog.tistory.com/attachment/cfile9.uf@12607A434EE866A6161316.zip&quot;&gt;&lt;img src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/blog/image/extension/zip.gif&quot; alt=&quot;&quot; style=&quot;vertical-align: middle;&quot; /&gt; sha256.zip&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;
&lt;P&gt;바이너리의 무결성 체크를 위해 hash를 사용하는데,&lt;br /&gt;
주로 SHA를 이용합니다.&lt;br /&gt;
최근에 현업에서 SHA256(혹은 SHA2)의 요구조건이 있는데,&lt;br /&gt;
불행하게도 Win32 API로는 SHA2를 구하는데 제약사항이 있습니다.&lt;br /&gt;
(ALG_ID(&lt;A title=&quot;[http://msdn.microsoft.com/en-us/library/windows/desktop/aa375549(v=vs.85).aspx]로 이동합니다.&quot; href=&quot;http://msdn.microsoft.com/en-us/library/windows/desktop/aa375549(v=vs.85).aspx&quot; target=_blank&gt;링크&lt;/A&gt;)를 보면, SHA256은 대체적으로 Vista 이상의 OS에서 지원됩니다.)&lt;br /&gt;
&lt;br /&gt;그래서, SHA256을 직접 구현해야 되는데,&lt;br /&gt;
문제는 &quot;버그&quot;입니다. 즉, Hash라는 중요한 모듈에 버그가 있다면, 큰일날 노릇이죠.&lt;br /&gt;
그래서 안정성있는 코드를 사용하는것은 무었보다도 중요합니다.&lt;br /&gt;
&lt;br /&gt;보통 openssl에도 sha256이 있는데,&lt;br /&gt;
openssl은,&lt;/P&gt;
&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;빌드가 쉽지않다. (즉, SHA256 부분만 가져오기가 힘들다)&lt;/LI&gt;
&lt;LI&gt;라이선스가 좀 까다롭다&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;와 같은 제약이 있습니다.&lt;br /&gt;
&lt;br /&gt;그래서 알아본 결과 crypto++ 이라는 라이브러리가 있던데,&lt;br /&gt;
FIPS-2 Level 1 통과도 되었으니, 나름 안정성있는 코드라 봅니다.&lt;br /&gt;
물론 Public Domain이라 사용 제한도 없구요.&lt;br /&gt;
&lt;br /&gt;문제는, crypto++를 가져오고 빌드하는 문제입니다.&lt;br /&gt;
물론, crypto++도 VC 빌드가 있으나,&lt;br /&gt;
전체가 아니라, sha256 부분만 가져오도록 하는것이 본 블로그 포스트의 목적입니다.&lt;br /&gt;
&lt;br /&gt;빌드를 완성시킨, sha256을 공유하니 확인해 보시기 바랍니다.&lt;br /&gt;
우선, x64 platform까지 추가된 프로젝트를 가정하고,&lt;br /&gt;
상위 경로에 Common에 CryptoppSHA256.cpp/.h가 Main Body이며,&lt;br /&gt;
상위 경로에 OpenSrc\cryptopp561에 crypto++ 코드가 들어있다고 가정합니다.&lt;br /&gt;
&lt;br /&gt;개발의 귀차니즘으로 CryptoppSHA256.cpp는 CString을 사용하는데,&lt;br /&gt;
ATL 정도만 Link하면 빌드가 됩니다.&lt;br /&gt;
물론, ATL 사용이 어렵다면, CString&amp;nbsp;대신 TCHAR buffer가 들어가도록 구현하세요.&lt;br /&gt;
그러면 순수 C++로 구현이 될 것입니다.&lt;br /&gt;
&lt;br /&gt;우선, 아래와 같이 crypto++의 .cpp 코드를 가져오기 합니다.&lt;br /&gt;
물론, SHA256 실행을 위한 최소한의 코드입니다.&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile22.uf.tistory.com/original/1660063A4EE863AE31BDAD&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile22.uf.tistory.com/image/1660063A4EE863AE31BDAD&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;001.png&quot; height=&quot;377&quot; width=&quot;362&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;위와 같은 cpp 목록의 속성을 들어가 precompile header를 Off 시킵니다.&lt;br /&gt;
이런 작업은 되도록 &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;All Configuration &amp;amp; All Platfoms&lt;/STRONG&gt;&lt;/FONT&gt;로 하시기 바랍니다.&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile8.uf.tistory.com/original/177C97344EE863F5271E81&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile8.uf.tistory.com/image/177C97344EE863F5271E81&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;002.png&quot; height=&quot;175&quot; width=&quot;620&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;그리고, 아래의 2개의 cpp를 추가합니다. 물론, precompile header도 Off 시킵니다.&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile22.uf.tistory.com/original/1419F63B4EE8643504D0DA&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile22.uf.tistory.com/image/1419F63B4EE8643504D0DA&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;003.png&quot; height=&quot;561&quot; width=&quot;357&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;그리고 위 2개의 파일을 X64에서만 빌드되도록 합니다.&lt;br /&gt;
즉, 위 2개의 파일의 속성에서, &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;All Configurations &amp;amp;&amp;nbsp;Win32&lt;/FONT&gt;&lt;/STRONG&gt; 조합으로, Excluded From Build를 Yes합니다.&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile29.uf.tistory.com/original/127EDF3A4EE864830BC453&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile29.uf.tistory.com/image/127EDF3A4EE864830BC453&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;004.png&quot; height=&quot;130&quot; width=&quot;581&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;그리고, x64dll.asm을 추가합니다.&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile24.uf.tistory.com/original/126409384EE864FD0AB12A&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile24.uf.tistory.com/image/126409384EE864FD0AB12A&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;005.png&quot; height=&quot;545&quot; width=&quot;620&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
위와 같이 창이 뜨면 Cancel 하시기 바랍니다.&lt;br /&gt;
&lt;br /&gt;x64dll.asm도 아까전의 2개 파일처럼 x64에서만 빌드되도록 합니다.&lt;br /&gt;
&lt;br /&gt;그리고, 마지막으로, 프로젝트의 .vcproj에서 x64dll.asm이 선언된 부분을 아래의 내용으로 overwrite합니다.&lt;br /&gt;
(tab이 깨지는데, 정확한 내용은 sha256.zip::CrpytoSHA256\CrpytoSHA256.vcproj를 참고하세요)&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#eaf4cf&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;100%&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;File&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;RelativePath=&quot;..\OpenSrc\cryptopp561\x64dll.asm&quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;FileConfiguration&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Name=&quot;Debug|Win32&quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ExcludedFromBuild=&quot;true&quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;Tool&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Name=&quot;VCCustomBuildTool&quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/FileConfiguration&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;FileConfiguration&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Name=&quot;Debug|x64&quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;Tool&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Name=&quot;VCCustomBuildTool&quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CommandLine=&quot;ml64.exe /c /nologo /Fo&amp;amp;quot;$(IntDir)\x64dll.obj&amp;amp;quot; /Zi &amp;amp;quot;$(InputPath)&amp;amp;quot;&amp;amp;#x0D;&amp;amp;#x0A;&quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Outputs=&quot;$(IntDir)\x64dll.obj&quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/FileConfiguration&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;FileConfiguration&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Name=&quot;Release|Win32&quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ExcludedFromBuild=&quot;true&quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;Tool&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Name=&quot;VCCustomBuildTool&quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/FileConfiguration&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;FileConfiguration&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Name=&quot;Release|x64&quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;Tool&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Name=&quot;VCCustomBuildTool&quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CommandLine=&quot;ml64.exe /c /nologo /Fo&amp;amp;quot;$(IntDir)\x64dll.obj&amp;amp;quot; /Zi &amp;amp;quot;$(InputPath)&amp;amp;quot;&amp;amp;#x0D;&amp;amp;#x0A;&quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Outputs=&quot;$(IntDir)\x64dll.obj&quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/FileConfiguration&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/File&amp;gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;
이렇게 하면, Win32와 x64모두 빌드가 됩니다.&lt;br /&gt;
&lt;br /&gt;첨부된 sample은 &quot;abc&quot;에 대한 sha256 값을 검증하는 내용입니다.&lt;br /&gt;
코드는,&lt;br /&gt;
#include &quot;CryptoppSHA256.h&quot;&lt;br /&gt;
...&lt;br /&gt;
CString strSHA256;&lt;br /&gt;
...&lt;br /&gt;
&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;CCryptoppSHA256&lt;/STRONG&gt;&lt;/FONT&gt;::&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;GetSHA256AndVerify&lt;/FONT&gt;&lt;/STRONG&gt;((LPBYTE)&quot;abc&quot;, 3, strSHA256);&lt;br /&gt;
와 같이 하면 됩니다.&lt;br /&gt;
리턴값은 Win32 ErrorCode입니다.&lt;br /&gt;
&lt;br /&gt;CString을 사용하기 때문에, ATL이나 MFC를 사용합니다.&lt;br /&gt;
물론, TCHAR 버퍼를 사용하도록 코드 수정 하면 해당 의존성은 제거될 것입니다.&lt;br /&gt;
&lt;br /&gt;cryptopp561의 testvectors 경로에 sha.txt가 있습니다.&lt;br /&gt;
그곳의 내용으로 verify할 수 있습니다.&lt;br /&gt;
물론, Win32 / x64 모두 제대로 동작함을 알 수 있습니다.&lt;/P&gt;&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-116-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-116-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=23530241&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/116&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/프로그래밍&quot;&gt;프로그래밍&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/프로그래밍/Let%27s%20Share%20it&quot;&gt;Let's Share it&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/118&quot; &gt;프로세스 생성 종결자 (ShellExecute / CreateProcess)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/117&quot; &gt;손쉽게 File을 나열할 수 있는 class 공유(FindFirstFile/FindNextFile Wrapper)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/116&quot; &gt;VC9.0에서 crypto++ library를 이용하여 SHA256(sha2) 구하기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/12/14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/115&quot; &gt;비동기(OVERLAPPED I/O, IOCP, Thread Pool) IPC PIPE Class 공유&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/12/14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/114&quot; &gt;[ATL/MFC/C++] Ini Parser(ini 파서)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/11/30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/110&quot; &gt;concat과 printf를 동시에 수행하는 함수 공유&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/10/14&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>Let's Share it</category>
			<category>crypto++</category>
			<category>sha256</category>
			<category>무결성</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/116</guid>
			<comments>http://greenfishblog.tistory.com/116#entry116comment</comments>
			<pubDate>Wed, 14 Dec 2011 18:09:28 +0900</pubDate>
		</item>
		<item>
			<title>비동기(OVERLAPPED I/O, IOCP, Thread Pool) IPC PIPE Class 공유</title>
			<link>http://greenfishblog.tistory.com/115</link>
			<description>&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock center&quot; style=&quot;text-align: center; clear: both;&quot;&gt;&lt;a href=&quot;http://greenfishblog.tistory.com/attachment/cfile23.uf@203FBC3E4EE84CA30B918B.zip&quot;&gt;&lt;img src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/blog/image/extension/zip.gif&quot; alt=&quot;&quot; style=&quot;vertical-align: middle;&quot; /&gt; PipeIpc.zip&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;
&lt;P&gt;일반적으로 .exe간 통신을 위해서 PIPE를 흔히 사용하곤 합니다.&lt;br /&gt;
보통 그런 경우, 수신 Part(즉, Server side)에서는 Thread를 만들기도 합니다.&lt;br /&gt;
그래서, 보통의 PIPE skeleton은 thread 생성 코드가 포함됩니다.&lt;br /&gt;
혹은, 수신 Part에서는 지속적인 Loop를 돌기때문에, 어쩔수 없이 Caller는 Thread를 만들어 호출해야 합니다.&lt;br /&gt;
즉,&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile29.uf.tistory.com/original/150667454EE83B4E26D34A&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile29.uf.tistory.com/image/150667454EE83B4E26D34A&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;001.png&quot; height=&quot;175&quot; width=&quot;332&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
와 같이 호출자체가 block되는 구조이기 때문에, caller는 다른 작업을 진행하기 위해&lt;br /&gt;
thread를 만들어야 합니다.&lt;br /&gt;
&lt;br /&gt;이것을 방지하기 위해, 본 IPC PIPE는 IOCP와 Thread pool을 사용하였으며,&lt;br /&gt;
물론, 내부적으로도 CreateThread나 _beginthreadex를 전혀 사용하지 않았습니다.&lt;br /&gt;
&lt;br /&gt;즉, 다음과 같은 구조가 됩니다.&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile7.uf.tistory.com/original/155BDC414EE83B601AEF5B&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile7.uf.tistory.com/image/155BDC414EE83B601AEF5B&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;002.png&quot; height=&quot;152&quot; width=&quot;294&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
즉, 모든것은 Primary thread에서 진행되며, block과정은 없습니다.&lt;br /&gt;
그리고, 접속이 들어왔을 때, 그때 OS에서 생성해준 Thread에서 우리는&lt;br /&gt;
PIPE 작업을 하게 됩니다. 그러니, CreateThread나 _beginthreadex를 사용하지&lt;br /&gt;
않게 되죠.&lt;br /&gt;
&lt;br /&gt;이러한 구현을 위해 필요한 것이 Overlapped i/o와 ::&lt;A title=&quot;[http://msdn.microsoft.com/en-us/library/windows/desktop/ms685061(v=vs.85).aspx]로 이동합니다.&quot; href=&quot;http://msdn.microsoft.com/en-us/library/windows/desktop/ms685061(v=vs.85).aspx&quot; target=_blank&gt;RegisterWaitForSingleObject&lt;/A&gt; 입니다.&lt;br /&gt;
즉, 위 block되는 함수들 특징이, ::ReadFile / ::WriteFile를 사용할때, Overlapped I/O를&lt;br /&gt;
사용하지 않기 때문입니다.&lt;br /&gt;
그리고, 접속 체크를 위해 WaitForSingle(*Multiple)Object를 사용하면 block됩니다.&lt;br /&gt;
만일, ::RegisterWaitForSingleObject를 사용한다면, I/O 완료(Completion)때 호출될 callback만&lt;br /&gt;
등록하고 그 함수는 pass되는데, 그렇게 되면 완전한 non-block Server가 구현됩니다.&lt;br /&gt;
&lt;br /&gt;&lt;A title=&quot;[http://msdn.microsoft.com/en-us/library/windows/desktop/aa365146(v=vs.85).aspx]로 이동합니다.&quot; href=&quot;http://msdn.microsoft.com/en-us/library/windows/desktop/aa365146(v=vs.85).aspx&quot; target=_blank&gt;ConnectNamedPipe&lt;/A&gt;는 PIPE 접속을 기다리는 함수로, Overlapped I/O를 사용하지 않으면,&lt;br /&gt;
Block됩니다. 그래서 lpOverlapped를 만들어 전달하면 Block되지 않습니다.&lt;br /&gt;
그러면, 해당 I/O가 완료(Completion)된 싯점을 어떻게 알게 되냐?가 문제됩니다.&lt;br /&gt;
일반적으로, Overlapped I/O의 event를 ::WaitForSingleObject(...)로 진행하게되는데,&lt;br /&gt;
그러면 또 자체적인 block함수를 만들게 됩니다.&lt;br /&gt;
따라서, 해당 싯점을 ::RegisterWaitForSingleObject(...)를 사용하여 비동기적으로 알 수 있다면,&lt;br /&gt;
문제를 완벽하게 해결할 수 있습니다.&lt;br /&gt;
&lt;br /&gt;즉,&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#eaf4cf&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;100%&quot;&gt;// 만드시 ManualReset을 FALSE로 해야 한다.&lt;br /&gt;
overlap.hEvent = ::CreateEvent(NULL, &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;FALSE&lt;/FONT&gt;&lt;/STRONG&gt;, FALSE, NULL);&lt;br /&gt;
::&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;RegisterWaitForSingleObject&lt;/FONT&gt;&lt;/STRONG&gt;(&amp;amp;m_hWait, overlap.h, &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;OnConnect&lt;/FONT&gt;&lt;/STRONG&gt;, ....);&lt;br /&gt;
::ConnectNamedPipe(hPipe, &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&amp;amp;&lt;/FONT&gt;&lt;FONT color=#ff8b16&gt;overlap&lt;/FONT&gt;&lt;/STRONG&gt;);&lt;br /&gt;
&lt;br /&gt;// block되지 않고 넘어감.&lt;br /&gt;
...&lt;br /&gt;
...&lt;br /&gt;
...&lt;br /&gt;
// ConnectNamedPipe I/O 완료(Completion)시 호출받음.&lt;br /&gt;
// 물론, OS에서 관리하는 Thread Pool내에서 호출 받음 (자세한건 RegisterWaitForSingleObject flag 참고)&lt;br /&gt;
VOID CALLBACK &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;OnConnect&lt;/FONT&gt;&lt;/STRONG&gt;(PVOID lpParameter, BOOLEAN TimerOrWaitFired)&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;와 같은 구조가 됩니다.&lt;br /&gt;
&lt;br /&gt;물론, ConectNamedPipe(...)이후의 코드가 다른 Thread에서 생성되기 때문에,&lt;br /&gt;
디버깅이 힘든 단점이 있습니다. 허나, 프로그램의 효율을 높이기 위해서는 어쩔수 없는 선택이죠.&lt;br /&gt;
왜 이것이 효율이 높냐면, OS의 Thread Pool을 사용하기 때문입니다.&lt;br /&gt;
즉, 만들어진 Thread를 계속 재활용하기 때문에, Thread 생성의 부하가 줄어듭니다.&lt;br /&gt;
그리고, Event등 I/O 수신을 위해 불필요하게 생성되는 Thread의 개수를 줄일 수 있기 떄문입니다.&lt;br /&gt;
즉, 만약, Connection이 자주 발생하지 않는 프로그램인 경우,&amp;nbsp;시작부터 Thread를 생성하는것이&lt;br /&gt;
낭비이기 때문입니다. (* 참고로, ::RegisterWaitForSingleObject를 호출하면 최소 2~3개의 Thread가&lt;br /&gt;
생성됩니다. 만일, Connection의 개수가 1~2개를 넘기지 않는다면, 전통적 방법을 생각해 보세요)&lt;br /&gt;
&lt;br /&gt;이제, CPipeServer / CPipeClient / CPipeData를 소개해야 겠습니다.&lt;br /&gt;
물론, CCL 라이센스이기 때문에, 상업적 이용은 불가하며, 컨텐츠 변경은 가능합니다.&lt;br /&gt;
상업적 이용을 위해서는 저에게 간단히 contact해 주시기 바랍니다.&lt;br /&gt;
&lt;br /&gt;자세한 코드는 Pipelpc.zip을 참고하시기 바랍니다.&lt;/P&gt;
&lt;DIV style=&quot;BORDER-BOTTOM: #ec9c2c 1px solid; BORDER-LEFT: #ec9c2c 1px solid; PADDING-BOTTOM: 10px; BACKGROUND-COLOR: #f3d756; PADDING-LEFT: 10px; PADDING-RIGHT: 10px; BORDER-TOP: #ec9c2c 1px solid; BORDER-RIGHT: #ec9c2c 1px solid; PADDING-TOP: 10px&quot; class=txc-textbox&gt;DWORD &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;CPipeServer&lt;/STRONG&gt;&lt;/FONT&gt;::&lt;STRONG&gt;StartService&lt;/STRONG&gt;&lt;br /&gt;
[IN] LPCTSTR &lt;EM&gt;lpszChannelId&lt;/EM&gt;&lt;br /&gt;
[IN] PFN_OnRequest &lt;EM&gt;pfnOnRequest&lt;/EM&gt;&lt;br /&gt;
[OPTIONAL IN] LPVOID &lt;EM&gt;pContext&lt;/EM&gt;&lt;br /&gt;
&lt;/DIV&gt;&lt;br /&gt;
Service를 시작합니다.&lt;br /&gt;
물론, 바로 리턴이 이뤄지며, 해당 과정에서 코드상 Thread 생성 부분은&amp;nbsp;없습니다.&lt;br /&gt;
(::RegisterWaitForSingleObject(...)호출로 인해 기본적인 2~3개 생성됨. 이는 OS에서 관리됨)&lt;br /&gt;
&lt;br /&gt;ChannelID는 통신을 위한 channel명이 됩니다.&lt;br /&gt;
이미 Channel이 열려있다면 실패하게 됩니다. (PIPE instance를 1개로 설정함)&lt;br /&gt;
물론, 해당 코드를 좀 수정하면, 여러개의 instance 생성이 가능합니다.&lt;br /&gt;
&lt;br /&gt;Win32 ErrorCode가 리턴됩니다.&lt;br /&gt;
&lt;br /&gt;pfnOnRequest는&lt;br /&gt;
VOID OnRequest(IN CPipeData&amp;amp; cInPipeData, OUT CPipeData&amp;amp; cOutPipeData, IN LPVOID pContext)&lt;br /&gt;
형태로, Caller에서 전달한 데이터(cInPipeData)와 Caller에 전달할 데이터(cOutPipeData), 그리고,&lt;br /&gt;
StartService의 pContext를 전달&lt;br /&gt;
받는 함수 포인터입니다.&lt;br /&gt;
즉, Caller와 접속이 이뤄지면, 해당 callback이 호출된다고 보면 됩니다.&lt;br /&gt;
물론, 다른 임의의 Thread에서 호출받음을 명심하세요.&lt;br /&gt;
&lt;br /&gt;pContext는 callback 함수에 전달될 data 입니다.&lt;br /&gt;
&lt;br /&gt;본 함수가 non-block인 관계로, 언제까지 Listen하냐면,&lt;br /&gt;
StopService 호출 혹은 파괴자 호출입니다.&lt;br /&gt;
즉, Class Instance가 유지되는 동안은 Listen이 이뤄집니다.&lt;br /&gt;
&lt;br /&gt;
&lt;DIV style=&quot;BORDER-BOTTOM: #ec9c2c 1px solid; BORDER-LEFT: #ec9c2c 1px solid; PADDING-BOTTOM: 10px; BACKGROUND-COLOR: #f3d756; PADDING-LEFT: 10px; PADDING-RIGHT: 10px; BORDER-TOP: #ec9c2c 1px solid; BORDER-RIGHT: #ec9c2c 1px solid; PADDING-TOP: 10px&quot; class=txc-textbox&gt;VOID &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;CPipeServer&lt;/STRONG&gt;&lt;/FONT&gt;::&lt;STRONG&gt;StopService&lt;/STRONG&gt;&lt;br /&gt;
&lt;/DIV&gt;&lt;br /&gt;
시작중인 서비스를 중단시킵니다.&lt;br /&gt;
현재 진행중인 callback이 있다면, 종료때까지 block됩니다.&lt;br /&gt;
&lt;br /&gt;
&lt;DIV style=&quot;BORDER-BOTTOM: #ec9c2c 1px solid; BORDER-LEFT: #ec9c2c 1px solid; PADDING-BOTTOM: 10px; BACKGROUND-COLOR: #f3d756; PADDING-LEFT: 10px; PADDING-RIGHT: 10px; BORDER-TOP: #ec9c2c 1px solid; BORDER-RIGHT: #ec9c2c 1px solid; PADDING-TOP: 10px&quot; class=txc-textbox&gt;BOOL&amp;nbsp;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;CPipeClient&lt;/STRONG&gt;&lt;/FONT&gt;::&lt;STRONG&gt;AddParam&lt;/STRONG&gt;&lt;br /&gt;
[IN] LPCTSTR &lt;EM&gt;lpszParamName&lt;/EM&gt;&lt;br /&gt;
[IN] LPBYTE &lt;EM&gt;pBuf&lt;/EM&gt;&lt;br /&gt;
[IN] size_t &lt;EM&gt;dwCbSize&lt;/EM&gt;&lt;br /&gt;
&lt;/DIV&gt;&lt;br /&gt;
Server에 전달할 Parameter들을 추가합니다.&lt;br /&gt;
물론, CallService하기전에 이뤄져야 합니다.&lt;br /&gt;
성공시 TRUE, 실패시 FALSE가 리턴됩니다.&lt;br /&gt;
&lt;br /&gt;lpszParameterName은 변수명을 의미합니다.&lt;br /&gt;
*|=등의 문자는 불허하며, 중복으로 들어가는 경우도 불허합니다.&lt;br /&gt;
&lt;br /&gt;pBuf는 전달될 BYTE buffer입니다.&lt;br /&gt;
dwCbSize는 전달할 buffer의 BYTE 크기 입니다.&lt;br /&gt;
&lt;br /&gt;
&lt;DIV style=&quot;BORDER-BOTTOM: #ec9c2c 1px solid; BORDER-LEFT: #ec9c2c 1px solid; PADDING-BOTTOM: 10px; BACKGROUND-COLOR: #f3d756; PADDING-LEFT: 10px; PADDING-RIGHT: 10px; BORDER-TOP: #ec9c2c 1px solid; BORDER-RIGHT: #ec9c2c 1px solid; PADDING-TOP: 10px&quot; class=txc-textbox&gt;DWORD &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;CPipeClient&lt;/STRONG&gt;&lt;/FONT&gt;::&lt;STRONG&gt;CallService&lt;/STRONG&gt;&lt;br /&gt;
[IN] LPCTSTR &lt;EM&gt;lpszChannelId&lt;/EM&gt;&lt;br /&gt;
[OUT] CPipeData&amp;amp; &lt;EM&gt;cOutPipeData&lt;/EM&gt;&lt;br /&gt;
[IN OPTIONAL] DWORD &lt;EM&gt;dwConnectTimeoutSec&lt;/EM&gt;&lt;br /&gt;
&lt;/DIV&gt;&lt;br /&gt;
Service를 호출합니다.&lt;br /&gt;
서비스 응답까지 Block됩니다.&lt;br /&gt;
해당 서비스가 이전의 요청사항을 처리중 혹은 아직 실행이 안되었을 때,&lt;br /&gt;
Connect Timeout 만큼 기다려 줍니다. 해당 값의 단위는 초(sec)입니다.&lt;br /&gt;
그리고 Win32 ErrorCode를 리턴합니다.&lt;br /&gt;
&lt;br /&gt;lpszChannelId는 통신할 channel 명을 의미합니다.&lt;br /&gt;
cOutPipeData는 서버로부터 응답받은 데이터입니다.&lt;br /&gt;
dwConnectTimeoutSec는 접속을 위한 Timeout 값(초)입니다. 이는 접속을 위한 시간값이지,&lt;br /&gt;
CallService 실행시간을 의미하진 않습니다.&lt;br /&gt;
&lt;br /&gt;
&lt;DIV style=&quot;BORDER-BOTTOM: #ec9c2c 1px solid; BORDER-LEFT: #ec9c2c 1px solid; PADDING-BOTTOM: 10px; BACKGROUND-COLOR: #f3d756; PADDING-LEFT: 10px; PADDING-RIGHT: 10px; BORDER-TOP: #ec9c2c 1px solid; BORDER-RIGHT: #ec9c2c 1px solid; PADDING-TOP: 10px&quot; class=txc-textbox&gt;BOOL &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;CPipeData&lt;/FONT&gt;&lt;/STRONG&gt;::&lt;STRONG&gt;SetParam&lt;/STRONG&gt;&lt;br /&gt;
[IN] LPCTSTR &lt;EM&gt;lpszName&lt;/EM&gt;&lt;br /&gt;
[IN] LPBYTE &lt;EM&gt;pData&lt;/EM&gt;&lt;br /&gt;
[IN] size_t &lt;EM&gt;dwCbSize&lt;/EM&gt;&lt;br /&gt;
&lt;/DIV&gt;&lt;br /&gt;
Parameter를 설정합니다.&lt;br /&gt;
이전값이 있는 경우, 실패합니다.&lt;br /&gt;
성공시 TRUE, 실패시 FALSE를 리턴합니다.&lt;br /&gt;
&lt;br /&gt;lpszName은 Parameter의 이름을 설정합니다. *|=등의 문자는 불허합니다.&lt;br /&gt;
pData, dwCbSize는 들어갈 data와 크기입니다.&lt;br /&gt;
&lt;br /&gt;해당 호출은, 따로 메모리를 할당하여 보관하므로,&lt;br /&gt;
Caller는 해당 함수 호출후, 전달 데이터를 파괴해도 무방합니다.&lt;br /&gt;
&lt;br /&gt;
&lt;DIV style=&quot;BORDER-BOTTOM: #ec9c2c 1px solid; BORDER-LEFT: #ec9c2c 1px solid; PADDING-BOTTOM: 10px; BACKGROUND-COLOR: #f3d756; PADDING-LEFT: 10px; PADDING-RIGHT: 10px; BORDER-TOP: #ec9c2c 1px solid; BORDER-RIGHT: #ec9c2c 1px solid; PADDING-TOP: 10px&quot; class=txc-textbox&gt;BOOL &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;CPipeData&lt;/FONT&gt;&lt;/STRONG&gt;::&lt;STRONG&gt;GetParamPtr&lt;/STRONG&gt;&lt;br /&gt;
[IN] LPCTSTR &lt;EM&gt;lpszName&lt;/EM&gt;&lt;br /&gt;
[OPTIONAL OUT] LPBYTE* &lt;EM&gt;ppData&lt;/EM&gt;&lt;br /&gt;
[OPTIONAL OUT] size_t* &lt;EM&gt;pdwSize&lt;/EM&gt;&lt;br /&gt;
&lt;/DIV&gt;&lt;br /&gt;
Parameter를 구합니다.&lt;br /&gt;
값이 존재할시 TRUE를, 그 이외의 경우엔 FALSE를 리턴합니다.&lt;br /&gt;
&lt;br /&gt;lpszName은 구할 Parameter 이름입니다.&lt;br /&gt;
ppData는 전달받을 Data Pointer입니다. NULL 전달 가능합니다. 해당 Pointer는 내부에서 사용하는 메모리이므로,&lt;br /&gt;
read-only로 사용하시기 바랍니다.&lt;br /&gt;
pdwSize는 Data의 Byte크기를 전달합니다. NULL 전달 가능합니다.&lt;br /&gt;
&lt;br /&gt;
&lt;DIV style=&quot;BORDER-BOTTOM: #ec9c2c 1px solid; BORDER-LEFT: #ec9c2c 1px solid; PADDING-BOTTOM: 10px; BACKGROUND-COLOR: #f3d756; PADDING-LEFT: 10px; PADDING-RIGHT: 10px; BORDER-TOP: #ec9c2c 1px solid; BORDER-RIGHT: #ec9c2c 1px solid; PADDING-TOP: 10px&quot; class=txc-textbox&gt;VOID &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;CPipeData&lt;/FONT&gt;&lt;/STRONG&gt;::&lt;STRONG&gt;ClearAllParam&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;INT &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;CPipeData&lt;/FONT&gt;&lt;/STRONG&gt;::&lt;STRONG&gt;GetCount&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;BOOL &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;CPipeData&lt;/FONT&gt;&lt;/STRONG&gt;::&lt;STRONG&gt;GetName&lt;/STRONG&gt;&lt;br /&gt;
[IN] INT nIndex&lt;br /&gt;
[OUT] LPTSTR lpszName&lt;br /&gt;
[IN] size_t dwCchLength&lt;br /&gt;
&lt;/DIV&gt;&lt;br /&gt;
ClearAllParam은 모든 data를 삭제합니다.&lt;br /&gt;
&lt;br /&gt;GetCount는 Parameter의 개수를 구합니다.&lt;br /&gt;
&lt;br /&gt;GetName은 각 Index의 Parameter 이름을 구합니다.&lt;br /&gt;
&lt;br /&gt;
&lt;DIV style=&quot;BORDER-BOTTOM: #ec9c2c 1px solid; BORDER-LEFT: #ec9c2c 1px solid; PADDING-BOTTOM: 10px; BACKGROUND-COLOR: #f3d756; PADDING-LEFT: 10px; PADDING-RIGHT: 10px; BORDER-TOP: #ec9c2c 1px solid; BORDER-RIGHT: #ec9c2c 1px solid; PADDING-TOP: 10px&quot; class=txc-textbox&gt;VOID &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;CPipeData&lt;/STRONG&gt;&lt;/FONT&gt;::&lt;STRONG&gt;ToByteAlloc&lt;/STRONG&gt;&lt;br /&gt;
VOID &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;CPipeData&lt;/STRONG&gt;&lt;/FONT&gt;::&lt;STRONG&gt;FromByte&lt;/STRONG&gt;&lt;br /&gt;
VOID &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;CPipeData&lt;/STRONG&gt;&lt;/FONT&gt;::&lt;STRONG&gt;ToBase64Alloc&lt;/STRONG&gt;&lt;br /&gt;
VOID &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;CPipeData&lt;/STRONG&gt;&lt;/FONT&gt;::&lt;STRONG&gt;FromBase64&lt;/STRONG&gt;&lt;br /&gt;
VOID &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;CPipeData&lt;/STRONG&gt;&lt;/FONT&gt;::&lt;STRONG&gt;FreeAlloc&lt;/STRONG&gt;&lt;br /&gt;
&lt;/DIV&gt;&lt;br /&gt;
위 함수는 직접적으로 사용하지 않을 수 있습니다.&lt;br /&gt;
Parameter들을 Byte Stream으로 변환하는데 쓰이는 함수입니다.&lt;br /&gt;
즉, Pipe 통신시 실제로 위 함수를 이용하여 만들어진 Byte Stream으로 송/수신하게 됩니다.&lt;br /&gt;
&lt;br /&gt;물론, 보안을 위해 Base64를 간단히 이용하였습니다.&lt;br /&gt;
Pipe는 특징상 손쉽게 남이 훔쳐볼 수 있습니다.&lt;br /&gt;
그래서 보안상, 최소한의 손쉬운 인코딩(물론, 암호화는 아닙니다)을 가져온게 Base64입니다.&lt;br /&gt;
Base64는 ATL을 사용한다면 &amp;lt;atlenc.h&amp;gt;의 함수를 그대로 쓰면 되나,&lt;br /&gt;
혹시나 ATL을 사용하지 않는 project를 위해 ATL함수를 그대로 가져왔습니다.&lt;br /&gt;
(혹시 Microsoft ATL에 licensing이 있는지 모르겠습니다. 문제가 될때 삭제하겠습니다.)&lt;br /&gt;
&lt;br /&gt;물론, 알려진 Base64 또한 의미가 없습니다. 쉽게 잘 풀리니깐요.&lt;br /&gt;
그래서, Base64이되, 변환 Table을 변경하면, 쉽게는 뚤리지는 않습니다.&lt;br /&gt;
&lt;br /&gt;아래와 같이 수정 시나리오를 따르세요.&lt;br /&gt;
그러면 분석하기 힘든 바이너리 데이터로 송/수신하게 됩니다.&lt;br /&gt;
(물론 인코딩된거지 암호화된게 아니기 때문에, 완벽한 보안은 아닙니다.)&lt;br /&gt;
&lt;br /&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#eaf4cf&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #b8d63d 1px solid; BORDER-LEFT: #b8d63d 1px solid; BORDER-TOP: #b8d63d 1px solid; BORDER-RIGHT: #b8d63d 1px solid&quot; width=&quot;100%&quot;&gt;
&lt;P&gt;BOOL CPipeData::Base64Encode(&lt;br /&gt;
...&lt;br /&gt;
&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;&amp;nbsp;static const char s_chBase64EncodingTable[64] = {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;1, 2, 3,&amp;nbsp;... }; &lt;/STRONG&gt;&lt;/FONT&gt;&lt;FONT color=#2b8400&gt;&lt;STRONG&gt;--&amp;gt; (1)&lt;br /&gt;
&lt;/STRONG&gt;&lt;/FONT&gt;&lt;br /&gt;
&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;// &lt;/STRONG&gt;&lt;/FONT&gt;*szDest++ = '.';&lt;br /&gt;
&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;*szDest++ = 111;&lt;/FONT&gt;&lt;/STRONG&gt; &lt;FONT color=#2b8400&gt;&lt;STRONG&gt;--&amp;gt; (2)&lt;br /&gt;
&lt;/STRONG&gt;&lt;/FONT&gt;&lt;br /&gt;
int CPipeData::DecodeBase64Char(unsigned int ch) &lt;FONT color=#2b8400&gt;&lt;STRONG&gt;--&amp;gt; (3)&lt;br /&gt;
&lt;/STRONG&gt;&lt;/FONT&gt;{&lt;br /&gt;
&amp;nbsp;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;int i = 0;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&amp;nbsp;static const char s_chBase64DecodingTable[64] = {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;1, 2, 3,&amp;nbsp;... };&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&amp;nbsp;for (i=0; i&amp;lt;64; i++)&lt;br /&gt;
&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;if (s_chBase64DecodingTable[i] == ch)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;return i;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;}&lt;br /&gt;
&lt;/FONT&gt;&lt;/STRONG&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&amp;nbsp;return -1;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
}&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;
(1)에서 변환 table을 만듭니다. 0, 10, 13 값은 제외하도록 합니다. 물론 255보다 작아야 합니다.&lt;br /&gt;
되도록 값을 뒤 섞으십시요.&lt;br /&gt;
(2)에서 '.' 부분을 다른 값으로 변경합니다. 해당 값은 (1)의 table에 없어야 합니다.&lt;br /&gt;
(3)에서는 기존 코드를 변경합니다. (1) 변환 table을 가져오도록 합니다.&lt;br /&gt;
&lt;br /&gt;사용예는, 첨부된 Pipelpc.zip을 참고하시기 바랍니다.&lt;br /&gt;
Server/Client로 나눠진 프로젝트가 있으며, Common 경로에 Pipe 코드가 있습니다.&lt;br /&gt;
각 프로젝트 Debug에 .exe가 있습니다.(Static Link라 재배포팩 관련없습니다.)&lt;br /&gt;
Debug인 경우 printf되는 특징이 있어, Debug 빌드를 포함시켰습니다.&lt;br /&gt;
&lt;br /&gt;
&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;[INFO] Success to start service, &lt;/FONT&gt;&lt;A href=&quot;file://\\.\pipe\mychannel&quot;&gt;&lt;FONT color=#ffffff&gt;\\.\pipe\mychannel&lt;/FONT&gt;&lt;/A&gt;&lt;br /&gt;
&lt;FONT color=#ffffff&gt;[INFO] Start request, &lt;/FONT&gt;&lt;A href=&quot;file://\\.\pipe\mychannel&quot;&gt;&lt;FONT color=#ffffff&gt;\\.\pipe\mychannel&lt;/FONT&gt;&lt;/A&gt;&lt;br /&gt;
&lt;FONT color=#ffffff&gt;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv&lt;br /&gt;
[INFO] ****************&lt;br /&gt;
[INFO] Start DUMP Param&lt;br /&gt;
[INFO] ****************&lt;br /&gt;
[INFO][0] Name=foobar, Size=1, Data(UTF8)=&lt;br /&gt;
[INFO][1] Name=input_param, Size=58, Data(UTF8)=T&lt;br /&gt;
[INFO] *****************&lt;br /&gt;
[INFO] Finish DUMP Param&lt;br /&gt;
[INFO] *****************&lt;br /&gt;
[INPUT] TO_SERVER_SEND:call_pid=1764&lt;br /&gt;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;br /&gt;
[INFO] Finished request, &lt;/FONT&gt;&lt;A href=&quot;file://\\.\pipe\mychannel&quot;&gt;&lt;FONT color=#ffffff&gt;\\.\pipe\mychannel&lt;/FONT&gt;&lt;/A&gt;&lt;br /&gt;
&lt;FONT color=#ffffff&gt;[INFO] Start request, &lt;/FONT&gt;&lt;A href=&quot;file://\\.\pipe\mychannel&quot;&gt;&lt;FONT color=#ffffff&gt;\\.\pipe\mychannel&lt;/FONT&gt;&lt;/A&gt;&lt;br /&gt;
&lt;FONT color=#ffffff&gt;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv&lt;br /&gt;
[INFO] ****************&lt;br /&gt;
[INFO] Start DUMP Param&lt;br /&gt;
[INFO] ****************&lt;br /&gt;
[INFO][0] Name=foobar, Size=1, Data(UTF8)=&lt;br /&gt;
[INFO][1] Name=input_param, Size=58, Data(UTF8)=T&lt;br /&gt;
[INFO] *****************&lt;br /&gt;
[INFO] Finish DUMP Param&lt;br /&gt;
[INFO] *****************&lt;br /&gt;
[INPUT] TO_SERVER_SEND:call_pid=1764&lt;br /&gt;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;

&lt;TABLE style=&quot;BORDER-COLLAPSE: collapse&quot; cellSpacing=1 cellPadding=1 width=610 bgColor=#000000&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style=&quot;BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid&quot; width=&quot;100%&quot;&gt;&lt;FONT color=#ffffff&gt;[INFO] ****************&lt;br /&gt;
[INFO] Start DUMP Param&lt;br /&gt;
[INFO] ****************&lt;br /&gt;
[INFO][0] Name=hello, Size=40, Data(UTF8)=m&lt;br /&gt;
[INFO] *****************&lt;br /&gt;
[INFO] Finish DUMP Param&lt;br /&gt;
[INFO] *****************&lt;br /&gt;
[RESPONSE] my resoponse : 1808&lt;br /&gt;
[INFO] ****************&lt;br /&gt;
[INFO] Start DUMP Param&lt;br /&gt;
[INFO] ****************&lt;br /&gt;
[INFO][0] Name=hello, Size=40, Data(UTF8)=m&lt;br /&gt;
[INFO] *****************&lt;br /&gt;
[INFO] Finish DUMP Param&lt;br /&gt;
[INFO] *****************&lt;br /&gt;
[RESPONSE] my resoponse : 1808&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;br /&gt;
Server.exe를 실행하고 Client.exe를 실행하면 각각 위와 같습니다.&lt;br /&gt;
2개의 Process가 정보를 서로 교환합니다.&lt;br /&gt;
&lt;br /&gt;코드는 다음과 같습니다.&lt;br /&gt;
&lt;br /&gt;&lt;TEXTAREA class=c++ name=code&gt;// Server.cpp : Defines the entry point for the console application.
//

#include &quot;stdafx.h&quot;
#include &quot;PipeServer.h&quot;
#include &amp;lt;locale.h&amp;gt;
#include &amp;lt;strsafe.h&amp;gt;

VOID OnRequest(CPipeData&amp;amp; cIn, CPipeData&amp;amp; cOut, LPVOID pContext)
{
	PBYTE  pData    = NULL;
	size_t dwCbData = 0;
	TCHAR  szResponse[MAX_PATH] = {0,};

	_tprintf(TEXT(&quot;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\r\n&quot;));

	// _DEBUG일때 출력된다.
	cIn.DUMP();

	// Input Parameter 분석 가능
	if (TRUE == cIn.GetParamPtr(TEXT(&quot;input_param&quot;), &amp;amp;pData, &amp;amp;dwCbData))
	{
		// pData가 dwCbData 크기 만큼 들어온다.
		// 물론, pData의 내용을 건드려서는 안된다.
		//
		// 여기서는 문장을 찍짜!!
		// 끝에 \0이 포함된 스트링이다~!!! 라고 가정한다.
		_tprintf(TEXT(&quot;[INPUT] %s\r\n&quot;), pData);
	}

	/*
		LPC 요청의 처리 함수가 들어갈 것이다.
	*/

	// 오래 걸리는 작업이 있을 것이다.
	::Sleep(1000);

	// Response 전달 준비!
	StringCchPrintf(szResponse, MAX_PATH, TEXT(&quot;my resoponse : %d&quot;), ::GetCurrentProcessId());

	// Response Data 전달 세팅~!!!
	cOut.SetParam(TEXT(&quot;hello&quot;), (LPBYTE)szResponse, (_tcslen(szResponse)+1)*sizeof(TCHAR));

	_tprintf(TEXT(&quot;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\n&quot;));
}

int _tmain(int argc, _TCHAR* argv[])
{
	DWORD		dwRtnValue	= 0;
	HANDLE		hEvent		= ::CreateEvent(NULL, TRUE, FALSE, TEXT(&quot;Global\\stop_evnt&quot;));
	CPipeServer	cPipeServer;

	// 콘솔 한글 출력
	_tsetlocale(LC_ALL, TEXT(&quot;korean&quot;));

	// 서비스를 시작한다.
	// 바로 리턴된다.
	dwRtnValue = cPipeServer.StartService(TEXT(&quot;mychannel&quot;),
										  OnRequest, 
										  (LPVOID)1);
	if (ERROR_SUCCESS != dwRtnValue)
	{
		_tprintf(TEXT(&quot;[ERROR] Fail to Start Service, %d&quot;), dwRtnValue);
		goto FINAL;
	}

	// 종료 이벤트를 기다리자.
	// _kill.bat가 실행되면 중단된다.
	::WaitForSingleObject(hEvent, INFINITE);

FINAL:
	return 0;
}
&lt;/TEXTAREA&gt; &lt;br /&gt;
&lt;br /&gt;&lt;TEXTAREA class=c++ name=code&gt;int _tmain(int argc, _TCHAR* argv[])
{
	INT    i              = 0;
	BYTE   dummy		  = 1;
	TCHAR  szIn[MAX_PATH] = {0,};
	DWORD  dwRtnValue     = 0;
	LPBYTE pData		  = NULL;
	size_t dwCbSize		  = 0;
	CPipeData cOut;

	// 콘솔 한글 출력
	_tsetlocale(LC_ALL, TEXT(&quot;korean&quot;));

	for (i=0; i&amp;lt;100; i++)
	{
		CPipeClient cPipeClient;

		// Input 파라미터를 계산한다.
		StringCchPrintf(szIn, MAX_PATH, TEXT(&quot;TO_SERVER_SEND:call_pid=%d&quot;), ::GetCurrentProcessId());

		// Input 파라미터를 추가하고,
		if (ERROR_SUCCESS != cPipeClient.AddParam(TEXT(&quot;foobar&quot;), 
												  &amp;amp;dummy, 
												  sizeof(dummy)))
		{
			_tprintf(TEXT(&quot;[ERROR] Fail to AddParam\r\n&quot;));
			continue;
		}

		if (ERROR_SUCCESS != cPipeClient.AddParam(TEXT(&quot;input_param&quot;),
												  (LPBYTE)szIn,
												  (_tcslen(szIn)+1)*sizeof(TCHAR))) // 끝에 \0 추가를 위해 +1함
		{
			_tprintf(TEXT(&quot;[ERROR] Fail to AddParam\r\n&quot;));
			continue;
		}

		// 호출하자. 접속 timeout은 5초
		dwRtnValue = cPipeClient.CallService(TEXT(&quot;mychannel&quot;), cOut, 5);
		if (ERROR_SUCCESS != dwRtnValue)
		{
			_tprintf(TEXT(&quot;[ERROR] Fail to CallService, %d\r\n&quot;), dwRtnValue);
			continue;
		}

		// Server로 부터온 응답을 출력하자.
		// cOut.GetParamPtr(...)으로 값을 구할 수 있다.
		cOut.DUMP();

		if (TRUE == cOut.GetParamPtr(TEXT(&quot;hello&quot;), &amp;amp;pData, &amp;amp;dwCbSize))
		{
			_tprintf(TEXT(&quot;[RESPONSE] %s\r\n&quot;), (LPCTSTR)pData);
		}

		// 다른 Caller process와 경쟁 테스트를 위해 Sleep
		::Sleep(100);
	}

	return 0;
}
&amp;lt;SPAN id=tx_marker_caret&amp;gt;&amp;lt;/SPAN&amp;gt;&lt;/TEXTAREA&gt;&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-115-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-115-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=23525221&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/115&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/프로그래밍&quot;&gt;프로그래밍&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/프로그래밍/Let%27s%20Share%20it&quot;&gt;Let's Share it&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/117&quot; &gt;손쉽게 File을 나열할 수 있는 class 공유(FindFirstFile/FindNextFile Wrapper)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2012/03/23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/116&quot; &gt;VC9.0에서 crypto++ library를 이용하여 SHA256(sha2) 구하기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/12/14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/115&quot; &gt;비동기(OVERLAPPED I/O, IOCP, Thread Pool) IPC PIPE Class 공유&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/12/14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/114&quot; &gt;[ATL/MFC/C++] Ini Parser(ini 파서)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/11/30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/110&quot; &gt;concat과 printf를 동시에 수행하는 함수 공유&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/10/14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/94&quot; &gt;Window Event Log(윈도우 이벤트 로그) 읽기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/07/20&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>Let's Share it</category>
			<category>Asynchronous</category>
			<category>BASE64</category>
			<category>base64 table 변경</category>
			<category>IOCP</category>
			<category>IPC</category>
			<category>lpc</category>
			<category>Overlapped io</category>
			<category>pipe</category>
			<category>RegisterWaitForSingleObject</category>
			<category>threrad pool</category>
			<category>비동기</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/115</guid>
			<comments>http://greenfishblog.tistory.com/115#entry115comment</comments>
			<pubDate>Wed, 14 Dec 2011 16:24:25 +0900</pubDate>
		</item>
		<item>
			<title>[ATL/MFC/C++] Ini Parser(ini 파서)</title>
			<link>http://greenfishblog.tistory.com/114</link>
			<description>&lt;P&gt;ini 파서를 공유합니다.&lt;br /&gt;
그리고 일단 제가 공유하는 모든 코드들은,&lt;br /&gt;
CCL 파이센스이고, [ 상업적이용 Off / 코드 변경 Yes ] 이니,&lt;br /&gt;
용도에 맞게 사용하시기 바랍니다.&lt;br /&gt;
상업용도로 사용하시고자 한다면, 필히 저에게 알려주시기 바랍니다. (물론 공유는 해드립니다~)&lt;br /&gt;
&lt;br /&gt;일단, CIniParser Class를 공유하며,&lt;br /&gt;
각 API 설명은 아래와 같습니다.&lt;br /&gt;
&lt;br /&gt;내부적으로 CAtlMap을 사용하기 때문에 Get/Set 동작은 빠를 것으로 보입니다.&lt;br /&gt;
조건으로 Section명에 ;문자를 쓰면 안됩니다.&lt;/P&gt;
&lt;DIV style=&quot;BORDER-BOTTOM: #ec9c2c 1px solid; BORDER-LEFT: #ec9c2c 1px solid; PADDING-BOTTOM: 10px; BACKGROUND-COLOR: #f3d756; PADDING-LEFT: 10px; PADDING-RIGHT: 10px; BORDER-TOP: #ec9c2c 1px solid; BORDER-RIGHT: #ec9c2c 1px solid; PADDING-TOP: 10px&quot; class=txc-textbox&gt;BOOL &lt;STRONG&gt;Parse&lt;/STRONG&gt;(&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;IN&lt;/STRONG&gt;&lt;/FONT&gt; LPCTSTR lpszBuf)&lt;br /&gt;
&lt;/DIV&gt;&lt;br /&gt;
lpszBuf 내용을 받아 파싱합니다.&lt;br /&gt;
내부에 Map을 사용하므로, Caller는 본 함수 호출이후에 lpszBuf를 Free해도 됩니다.&lt;br /&gt;
성공시 TRUE, 실패시 FALSE를 리턴합니다.&lt;br /&gt;
&amp;nbsp; 
&lt;DIV style=&quot;BORDER-BOTTOM: #ec9c2c 1px solid; BORDER-LEFT: #ec9c2c 1px solid; PADDING-BOTTOM: 10px; BACKGROUND-COLOR: #f3d756; PADDING-LEFT: 10px; PADDING-RIGHT: 10px; BORDER-TOP: #ec9c2c 1px solid; BORDER-RIGHT: #ec9c2c 1px solid; PADDING-TOP: 10px&quot; class=txc-textbox&gt;BOOL &lt;STRONG&gt;GetIni&lt;/STRONG&gt;(&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;OUT&lt;/FONT&gt;&lt;/STRONG&gt; CString&amp;amp; strIni)&lt;br /&gt;
&lt;/DIV&gt;&lt;br /&gt;
메모리상에 있는 Map을 Ini 포맷으로 변경합니다.&lt;br /&gt;
아래의&amp;nbsp;Parse에&amp;nbsp;전달한 lpszBuf와 Section 이름등 순서가 변경될 수 있음을 유의하시기 바랍니다.&lt;br /&gt;
물론, SetString한 순서도 변경될 수 있습니다.&lt;br /&gt;
단, 하나의 Section명은&amp;nbsp;한번만 등장하는것은 보장해 드립니다.&lt;br /&gt;
즉,&lt;br /&gt;

&lt;DIV&gt;　&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;[a]&lt;br /&gt;
&lt;/STRONG&gt;&lt;/FONT&gt;　q=1&lt;br /&gt;
　[b]&lt;br /&gt;
　a=1&lt;br /&gt;
　&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;[a]&lt;br /&gt;
&lt;/STRONG&gt;&lt;/FONT&gt;　e=3&lt;br /&gt;
와 같이 [a]가 두번 등장하지&amp;nbsp;않고 다음과 같이 뭉쳐줍니다.&lt;br /&gt;
　&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;[a]&lt;br /&gt;
&lt;/STRONG&gt;&lt;/FONT&gt;　q=1&lt;br /&gt;
　e=3&lt;br /&gt;
　[b]&lt;br /&gt;
　a=1&lt;br /&gt;
&amp;nbsp; &lt;/DIV&gt;
&lt;DIV&gt;
&lt;DIV style=&quot;BORDER-BOTTOM: #ec9c2c 1px solid; BORDER-LEFT: #ec9c2c 1px solid; PADDING-BOTTOM: 10px; BACKGROUND-COLOR: #f3d756; PADDING-LEFT: 10px; PADDING-RIGHT: 10px; BORDER-TOP: #ec9c2c 1px solid; BORDER-RIGHT: #ec9c2c 1px solid; PADDING-TOP: 10px&quot; class=txc-textbox&gt;BOOL &lt;STRONG&gt;GetString&lt;/STRONG&gt;(&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;IN&lt;/FONT&gt;&lt;/STRONG&gt; LPCTSTR lpszSectionName, &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;IN&lt;/FONT&gt;&lt;/STRONG&gt; LPCTSTR lpszKeyName, &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;OUT &lt;/FONT&gt;&lt;/STRONG&gt;CString&amp;amp; strValue)&lt;br /&gt;
&lt;/DIV&gt;&lt;br /&gt;
메모리상에 있는 Map을 기반으로 GetPrivateProfileString과 같은 효과를 냅니다.&lt;br /&gt;
값이 있을때 TRUE, 없을때 FALSE를 리턴하니,&lt;br /&gt;
Caller에서 알아서 기본값 세팅을 하시기 바랍니다.&lt;br /&gt;
&amp;nbsp; 
&lt;DIV style=&quot;BORDER-BOTTOM: #ec9c2c 1px solid; BORDER-LEFT: #ec9c2c 1px solid; PADDING-BOTTOM: 10px; BACKGROUND-COLOR: #f3d756; PADDING-LEFT: 10px; PADDING-RIGHT: 10px; BORDER-TOP: #ec9c2c 1px solid; BORDER-RIGHT: #ec9c2c 1px solid; PADDING-TOP: 10px&quot; class=txc-textbox&gt;BOOL &lt;STRONG&gt;SetString&lt;/STRONG&gt;(&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;IN&lt;/FONT&gt;&lt;/STRONG&gt; LPCTSTR lpszSectionName, &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;IN&lt;/FONT&gt;&lt;/STRONG&gt; LPCTSTR lpszKeyName, &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;IN&lt;/FONT&gt;&lt;/STRONG&gt; LPCTSTR lpszValue)&lt;br /&gt;
&lt;/DIV&gt;&lt;br /&gt;
메모리상에 있는 Map을 수정합니다.&lt;br /&gt;
성공시 TRUE, 실패시 FALSE를 리턴합니다.&lt;br /&gt;
&lt;br /&gt;View Plain을 통하면 좀더 자세히 볼 수 있습니다.&lt;br /&gt;
참고로, 버그 회피를 위해, 해당 Class의 Instance은&lt;br /&gt;
Thread간 공유할 수 없도록 하였습니다.&lt;br /&gt;
Class의 Instance는 해당 Thread에서만 사용하도록 하십시요.&lt;br /&gt;
&lt;/DIV&gt;IniParser.h&lt;br /&gt;
&lt;TEXTAREA class=c++ name=code&gt;#pragma once

#include &amp;lt;atlcoll.h&amp;gt;

class CIniParser
{
public:
	CIniParser(void);
	~CIniParser(void);

public:
	BOOL Parse(IN LPCTSTR lpszBuf);
	BOOL GetIni(OUT CString&amp;amp; strIni);

public:
	BOOL GetString(IN LPCTSTR lpszSectionName, IN LPCTSTR lpszKeyName, OUT CString&amp;amp; strValue);
	BOOL SetString(IN LPCTSTR lpszSectionName, IN LPCTSTR lpszKeyName, IN LPCTSTR lpszValue);

protected:
	VOID GetUpperSectionName(IN LPCTSTR lpszLine, OUT CString&amp;amp; strSectionName);
	VOID AddMap(IN LPCTSTR lpszSectionName, IN LPCTSTR lpszLine);

protected:
	DWORD						m_dwThreadId;
	CAtlMap&amp;lt;CString,CString&amp;gt;	m_cMap;
	CString						m_strTmp;
	CString						m_strTmp2;
	CString						m_strTmp3;
	CString						m_strTmp4;
};
&lt;/TEXTAREA&gt; &lt;br /&gt;
&lt;br /&gt;IniParser.cpp&lt;br /&gt;
&lt;TEXTAREA class=c++ name=code&gt;#include &quot;StdAfx.h&quot;
#include &quot;IniParser.h&quot;
#include &amp;lt;strsafe.h&amp;gt;

CIniParser::CIniParser(void)
{
	m_dwThreadId = ::GetCurrentThreadId();
}

CIniParser::~CIniParser(void)
{
}

BOOL CIniParser::Parse(IN LPCTSTR lpszBuf)
{
	BOOL	bRtnValue	= TRUE;
	INT		i			= 0;
	INT		nLast		= 0;
	CString	strSectionName;
	CString	strLine;

	if (m_dwThreadId != ::GetCurrentThreadId())
	{
		return FALSE;
	}

	// Map 초기화
	m_cMap.RemoveAll();

	if (NULL == lpszBuf)
	{
		bRtnValue = FALSE;
		goto FINAL;
	}

	for (i=0; i&amp;lt;STRSAFE_MAX_CCH; i++)
	{
		if ((TEXT('\n') == lpszBuf[i]) ||
			(TEXT('\0') == lpszBuf[i]))
		{
			// parse !!!
			strLine.TrimRight(TEXT(&quot;\r\n&quot;));
			strLine.TrimLeft(TEXT(&quot;\r\n &quot;));

			if (TEXT('[') == strLine[0])
			{
				// 만일 [로 시작했다면,...
				GetUpperSectionName(strLine, strSectionName);
			}
			else
			{
				// Map에 추가
				AddMap(strSectionName, strLine);
			}

			// 다시 초기화
			strLine = TEXT(&quot;&quot;);
		}
		else
		{
			strLine.AppendChar(lpszBuf[i]);
		}

		if (TEXT('\0') == lpszBuf[i])
		{
			break;
		}
	}

FINAL:
	return bRtnValue;
}

VOID CIniParser::AddMap(IN LPCTSTR lpszSectionName, IN LPCTSTR lpszLine)
{
	INT nFind = -1;

	if (m_dwThreadId != ::GetCurrentThreadId())
	{
		return;
	}

	if (NULL == lpszLine)
	{
		return;
	}

	m_strTmp = lpszLine;
	if (TEXT(';') == m_strTmp[0])
	{
		// ;로 시작한다면, 주석 처리
		goto FINAL;
	}

	nFind = m_strTmp.Find(TEXT('='));
	if (-1 == nFind)
	{
		// = 가 없다???
		goto FINAL;
	}

	m_strTmp2 = m_strTmp.Mid(0, nFind);
	m_strTmp2.TrimRight(TEXT(&quot; &quot;));
	if (TRUE == m_strTmp2.IsEmpty())
	{
		goto FINAL;
	}

	m_strTmp3 = m_strTmp.Mid(nFind+1);

	// m_strTmp2=m_strTmp3
	// 와 같이 parse되었다.

	// 이제 Map에 추가하자.

	// Map에 축가할 Key는 SECTIONNAME;KEYNAME 와 같은 포맷이다.
	m_strTmp4.Format(TEXT(&quot;%s;%s&quot;), lpszSectionName, m_strTmp2);
	m_strTmp4.MakeUpper();

	// Map에 추가되었다.
	m_cMap.SetAt(m_strTmp4, m_strTmp3);

FINAL:
	return;
}

// lpszLine이 Section 포맷이 아니라면, strSectionName은 Old값을 유지한다.
// lpszLine은 왼쪽에 ' '으로 trim 되었다고 가정
VOID CIniParser::GetUpperSectionName(IN LPCTSTR lpszLine, OUT CString&amp;amp; strSectionName)
{
	INT		i			= 0;
	LPCTSTR	lpszFind	= NULL;
	LPCTSTR lpszFind2	= NULL;

	if (NULL == lpszLine)
	{
		return;
	}

	if (m_dwThreadId != ::GetCurrentThreadId())
	{
		return;
	}

	if (TEXT('[') != lpszLine[0])
	{
		return;
	}

	lpszFind = _tcschr(lpszLine, TEXT(']'));
	if (NULL == lpszFind)
	{
		return;
	}

	lpszFind2 = _tcschr(lpszLine, TEXT(';'));
	if (NULL != lpszFind2)
	{
		if (lpszFind2 &amp;lt; lpszFind)
		{
			// section명에 ;가 오면 안된다.
			return;
		}
	}

	if (1 == lpszFind - lpszLine)
	{
		return;
	}

	strSectionName = TEXT(&quot;&quot;);

	for (i=1; i&amp;lt;lpszFind - lpszLine; i++)
	{
		if (TEXT(';') == lpszLine[i])
		{
			break;
		}

		strSectionName.AppendChar(lpszLine[i]);
	}

	// 대문자로~!!!
	strSectionName.MakeUpper();
}

// 리턴 : TRUE(성공) / FALSE(실패)
BOOL CIniParser::SetString(IN LPCTSTR lpszSectionName, IN LPCTSTR lpszKeyName, IN LPCTSTR lpszValue)
{
	BOOL	bRtnValue = FALSE;
	CString	strKey;

	if ((NULL == lpszSectionName) || (NULL == lpszKeyName) || (NULL == lpszValue))
	{
		bRtnValue = FALSE;
		goto FINAL;
	}

	if (m_dwThreadId != ::GetCurrentThreadId())
	{
		return FALSE;
	}

	strKey.Format(TEXT(&quot;%s;%s&quot;), lpszSectionName, lpszKeyName);
	strKey.MakeUpper();
	m_cMap.SetAt(strKey, lpszValue);

	if (FALSE == m_cMap.Lookup(strKey, m_strTmp))
	{
		bRtnValue = FALSE;
		assert(FALSE);
		goto FINAL;
	}

	if (0 != _tcscmp(m_strTmp, lpszValue))
	{
		bRtnValue = FALSE;
		assert(FALSE);
		goto FINAL;
	}

	// 여기까지 왔다면 성공
	bRtnValue = TRUE;

FINAL:
	return bRtnValue;
}

// 리턴 : TRUE(있다) / FALSE(없다)
BOOL CIniParser::GetString(IN LPCTSTR lpszSectionName, IN LPCTSTR lpszKeyName, OUT CString&amp;amp; strValue)
{
	BOOL	bRtnValue = FALSE;
	CString	strKey;

	strValue = TEXT(&quot;&quot;);

	if ((NULL == lpszSectionName) || (NULL == lpszKeyName))
	{
		bRtnValue = FALSE;
		goto FINAL;
	}

	if (m_dwThreadId != ::GetCurrentThreadId())
	{
		bRtnValue = FALSE;
		goto FINAL;
	}

	strKey.Format(TEXT(&quot;%s;%s&quot;), lpszSectionName, lpszKeyName);
	strKey.MakeUpper();
	if (TRUE != m_cMap.Lookup(strKey, strValue))
	{
		// Map에 없다.
		bRtnValue = FALSE;
		strValue  = TEXT(&quot;&quot;);
		goto FINAL;
	}

	// 여기까지 왔다면 성공
	bRtnValue = TRUE;

FINAL:
	return bRtnValue;
}

BOOL CIniParser::GetIni(OUT CString&amp;amp; strIni)
{
	BOOL						bRtnValue	= TRUE;
	INT							nFind		= 0;
	POSITION					pos			= {0,};
	CString						strKey;
	CString						strValue;
	CString						strSectionName;
	CString						strKeyName;
	CString						strNewKey;
	CString						strLine;
	CString						strOld;
	CString						strNode;
	CAtlMap&amp;lt;CString,CString&amp;gt;	cMapFormat;

	strIni = TEXT(&quot;&quot;);

	if (m_dwThreadId != ::GetCurrentThreadId())
	{
		return FALSE;
	}
	
	pos = m_cMap.GetStartPosition();

	// 포맷 map을 만든다.
	// 즉,
	// (SEC1;KEY, VAL1), (SEC1;KEY2, VAL2), (SEC2;KEY1, VAL3), ...
	// 와 같은 map을
	// (SEC, KEY=VAL1\r\nKEY2=VAL2\r\n), (SEC2, KEY1=KEY3\r\n), ....
	// 로 변환한다.
	while (pos != NULL)
	{
		strKey		= m_cMap.GetKeyAt(pos);
		strValue	= m_cMap.GetNextValue(pos);

		nFind = strKey.Find(TEXT(';'));
		if (-1 == nFind)
		{
			assert(FALSE);
			continue;
		}

		strSectionName = strKey.Mid(0, nFind);
		strKeyName = strKey.Mid(nFind+1);

		strNewKey.Format(TEXT(&quot;[%s]&quot;), strSectionName);
		strLine.Format(TEXT(&quot;%s=%s\r\n&quot;), strKeyName, strValue);

		if (TRUE == cMapFormat.Lookup(strNewKey, strOld))
		{
			strLine.Insert(0, strOld);
		}

		cMapFormat.SetAt(strNewKey, strLine);
	}

	pos = cMapFormat.GetStartPosition();
	while (pos != NULL)
	{
		strKey		= cMapFormat.GetKeyAt(pos);
		strValue	= cMapFormat.GetNextValue(pos);
		
		strNode.Format(TEXT(&quot;%s\r\n%s\r\n&quot;), strKey, strValue);
		strIni.Insert(0, strNode);
	}

	strIni.TrimRight(TEXT(&quot;\r\n&quot;));

	// 여기까지 왔다면 성공
	bRtnValue = TRUE;

	return bRtnValue;
}
&lt;SPAN id=tx_marker_caret&gt;&lt;/SPAN&gt;&lt;/TEXTAREA&gt;&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-114-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-114-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=23038074&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/114&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/프로그래밍&quot;&gt;프로그래밍&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/프로그래밍/Let%27s%20Share%20it&quot;&gt;Let's Share it&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/116&quot; &gt;VC9.0에서 crypto++ library를 이용하여 SHA256(sha2) 구하기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/12/14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/115&quot; &gt;비동기(OVERLAPPED I/O, IOCP, Thread Pool) IPC PIPE Class 공유&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/12/14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/114&quot; &gt;[ATL/MFC/C++] Ini Parser(ini 파서)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/11/30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/110&quot; &gt;concat과 printf를 동시에 수행하는 함수 공유&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/10/14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/94&quot; &gt;Window Event Log(윈도우 이벤트 로그) 읽기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/07/20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/85&quot; &gt;Proxy 서버 구하기 (자동 구성 스크립트, pac)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/04/04&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>Let's Share it</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/114</guid>
			<comments>http://greenfishblog.tistory.com/114#entry114comment</comments>
			<pubDate>Wed, 30 Nov 2011 17:35:10 +0900</pubDate>
		</item>
		<item>
			<title>&quot;이 프로그램이 제대로 설치되지 않았을 수 있습니다.&quot; 대처 빌드 방법</title>
			<link>http://greenfishblog.tistory.com/113</link>
			<description>&lt;P&gt;설치프로그램등을 직접 만드는 경우, 파일명에 setup 등과 같은 이름이 들어가면,&lt;br /&gt;
종료후 다음과 같은 경고창이 뜰 수 있습니다. (Vista/Win7 이상)&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile4.uf.tistory.com/original/1207883C4ECDA17E26F916&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile4.uf.tistory.com/image/1207883C4ECDA17E26F916&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;001.png&quot; height=&quot;353&quot; width=&quot;432&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;파일명이 qqqq.exe라고 하더라도 발생하였습니다.&lt;br /&gt;
이런 정책은 Windows OS마다 변경될 수 있기 때문에, 명확한 대응법으로 막아야 합니다.&lt;br /&gt;
물론, 해당 실행파일이 코드 사이닝되어도 마찬가지 입니다.&lt;br /&gt;
&lt;br /&gt;해결법은,&lt;br /&gt;
&lt;A href=&quot;http://greenfishblog.tistory.com/13&quot; target=_blank&gt;2009/09/22 - [프로그래밍/Win32] - .exe에 Manifest 추가&lt;/A&gt;&lt;br /&gt;
를 참고하면 됩니다.&lt;br /&gt;
&lt;br /&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock center&quot; style=&quot;text-align: center; clear: both;&quot;&gt;&lt;a href=&quot;http://greenfishblog.tistory.com/attachment/cfile9.uf@1305C3394ECDA1EF28B109.xml&quot;&gt;&lt;img src=&quot;http://i1.daumcdn.net/cfs.tistory/v/110706133414/blog/image/extension/unknown.gif&quot; alt=&quot;&quot; style=&quot;vertical-align: middle;&quot; /&gt; add_manifest.xml&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;파일을 \res\add_manifest.xml로 복사합니다.&lt;br /&gt;
&lt;br /&gt;그리고,&lt;br /&gt;

&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile2.uf.tistory.com/original/156DE23B4ECDA2571D83E7&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile2.uf.tistory.com/image/156DE23B4ECDA2571D83E7&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;002.png&quot; height=&quot;222&quot; width=&quot;571&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;&lt;br /&gt;
와 같이 프로젝트 세팅을 진행하면 해당 문제는 발생하지 않습니다.&lt;br /&gt;
원인등은 검색해 보세요. 여기는 그냥 해결법만 제시합니다.~&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-113-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-113-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=22821544&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/113&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/프로그래밍&quot;&gt;프로그래밍&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/프로그래밍/Win32&quot;&gt;Win32&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/113&quot; &gt;&amp;quot;이 프로그램이 제대로 설치되지 않았을 수 있습니다.&amp;quot; 대처 빌드 방법&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/11/24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/112&quot; &gt;VC9.0 + MFC + StaticLink 시, gdiplus.dll 오류 해결법&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/11/17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/111&quot; &gt;WinInet으로 HTTP POST File Upload와 Data를 함께 보내기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/10/17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/98&quot; &gt;Internet Explorer_Hidden 윈도우 보호하기 (IE Web Control Message Hooking)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/08/20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/87&quot; &gt;DLL의 메모리릭을 쉽게 찾아 보기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/04/25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/84&quot; &gt;.exe의 export 함수를 이용한 개발 방법론 (공통함수 처리, 효율적인 Third-party plug-in 구조)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/03/31&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>Win32</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/113</guid>
			<comments>http://greenfishblog.tistory.com/113#entry113comment</comments>
			<pubDate>Thu, 24 Nov 2011 10:49:43 +0900</pubDate>
		</item>
		<item>
			<title>VC9.0 + MFC + StaticLink 시, gdiplus.dll 오류 해결법</title>
			<link>http://greenfishblog.tistory.com/112</link>
			<description>원문 : &lt;A href=&quot;http://www.indidev.net/forum/viewtopic.php?f=5&amp;amp;t=131&quot;&gt;http://www.indidev.net/forum/viewtopic.php?f=5&amp;amp;t=131&lt;/A&gt;&lt;br /&gt;
&lt;br /&gt;VC6.0를 넘어서는 compiler로 빌드되면&amp;nbsp;재배포팩 이슈가 항상 따라다닙니다.&lt;br /&gt;
그래서, 최초 실행/가동 프로그램(예, 설치프로그램)은&amp;nbsp;VC6.0으로 빌드하여,&lt;br /&gt;
의존성 문제를 원천봉쇄하기도 합니다.&lt;br /&gt;
&lt;br /&gt;되도록 VC6.0을 역사적 뒤안길로 보내버리기위해,&lt;br /&gt;
VC9.0으로 static link로 빌드 하면 문제가 없는 것으로 추측했으나,&lt;br /&gt;
gdiplus.dll의 의존성 문제가 발생합니다.&lt;br /&gt;
&lt;br /&gt;즉,&lt;br /&gt;

&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile7.uf.tistory.com/original/131BF3334EC4BAEA129DC3&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile7.uf.tistory.com/image/131BF3334EC4BAEA129DC3&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;001.png&quot; height=&quot;222&quot; width=&quot;401&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;&lt;br /&gt;

&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile2.uf.tistory.com/original/172A0C384EC4BAF7256039&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile2.uf.tistory.com/image/172A0C384EC4BAF7256039&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;002.png&quot; height=&quot;126&quot; width=&quot;472&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
와 같이 하여 mfc나 msvcrt* 같은 의존성은 없지만,&lt;br /&gt;
빌드본을 depends로 확인하면 아래와 같이 gdiplus.dll이 포함됩니다.&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile22.uf.tistory.com/original/180D2F354EC4BB24258EBD&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile22.uf.tistory.com/image/180D2F354EC4BB24258EBD&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;003.png&quot; height=&quot;329&quot; width=&quot;211&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;그런데, 문제는 Windows 2000 SP4 + IE5등 열약한 환경에서는 기본적으로 시스템에 gdiplus.dll이 포함되지&lt;br /&gt;
않습니다! 따라서 아래와 같은 현상이 발생합니다.&lt;br /&gt;
(DLL gdiplus.dll을(를) 지정한 경로 .... 에서 찾을 수 없습니다.)&lt;br /&gt;
&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile28.uf.tistory.com/original/201B10334EC4BB78158C87&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile28.uf.tistory.com/image/201B10334EC4BB78158C87&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;004.png&quot; height=&quot;153&quot; width=&quot;529&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;&lt;br /&gt;
Project Setting 수정으로 모든 방법을 동원해 봤는데, 해결되지 않았습니다.&lt;br /&gt;
해결법은, 단순히 theApp 클래스인 CWinAppEx를 CWinApp로 변경하고,&lt;br /&gt;
오류가 나면, CWinApp으로 replace해 주면 빌드가 완료되는데,&lt;br /&gt;
그 이후로는 gdiplus.dll이 떨어져나가며, 빌드본의 크기가 현격히! 줄어듭니다.&lt;br /&gt;
&lt;br /&gt;리본 컨트롤등을 사용하지 않는다면, 되도록 CWinApp을 사용하는것이 좋을 듯 합니다.&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-112-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-112-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=22599561&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/112&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/프로그래밍&quot;&gt;프로그래밍&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/프로그래밍/Win32&quot;&gt;Win32&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/113&quot; &gt;&amp;quot;이 프로그램이 제대로 설치되지 않았을 수 있습니다.&amp;quot; 대처 빌드 방법&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/11/24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/112&quot; &gt;VC9.0 + MFC + StaticLink 시, gdiplus.dll 오류 해결법&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/11/17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/111&quot; &gt;WinInet으로 HTTP POST File Upload와 Data를 함께 보내기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/10/17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/98&quot; &gt;Internet Explorer_Hidden 윈도우 보호하기 (IE Web Control Message Hooking)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/08/20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/87&quot; &gt;DLL의 메모리릭을 쉽게 찾아 보기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/04/25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/84&quot; &gt;.exe의 export 함수를 이용한 개발 방법론 (공통함수 처리, 효율적인 Third-party plug-in 구조)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/03/31&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>Win32</category>
			<category>gdiplus.dll 찾을 수 없습니다</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/112</guid>
			<comments>http://greenfishblog.tistory.com/112#entry112comment</comments>
			<pubDate>Thu, 17 Nov 2011 16:50:36 +0900</pubDate>
		</item>
		<item>
			<title>WinInet으로 HTTP POST File Upload와 Data를 함께 보내기</title>
			<link>http://greenfishblog.tistory.com/111</link>
			<description>생각보단 WinInet을 이용하여 Data나 File을 HTTP Post로 전송하는 자료가 많지 않더군요.&lt;br /&gt;
그래서 CHttpClient class를 공유합니다.&lt;br /&gt;

&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock center&quot; style=&quot;text-align: center; clear: both;&quot;&gt;&lt;a href=&quot;http://greenfishblog.tistory.com/attachment/cfile24.uf@206960504E9BDBFE2D1566.h&quot;&gt;&lt;img src=&quot;http://i1.daumcdn.net/cfs.tistory/v/110706133414/blog/image/extension/unknown.gif&quot; alt=&quot;&quot; style=&quot;vertical-align: middle;&quot; /&gt; HttpClient.h&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN: 0px&quot;&gt;&lt;div class=&quot;imageblock center&quot; style=&quot;text-align: center; clear: both;&quot;&gt;&lt;a href=&quot;http://greenfishblog.tistory.com/attachment/cfile10.uf@160977494E9BDC07218A69.cpp&quot;&gt;&lt;img src=&quot;http://i1.daumcdn.net/cfs.tistory/v/110706133414/blog/image/extension/unknown.gif&quot; alt=&quot;&quot; style=&quot;vertical-align: middle;&quot; /&gt; HttpClient.cpp&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;&lt;br /&gt;
다음과 같은 기능을 제공합니다.&amp;nbsp;&lt;br /&gt;

&lt;UL style=&quot;LIST-STYLE-TYPE: disc&quot;&gt;
&lt;LI&gt;File / Data 타입의 Post data 추가 기능 (Multi-Part로 전송)&lt;/LI&gt;
&lt;LI&gt;간단한 Encoding 기능&lt;/LI&gt;
&lt;LI&gt;Response Data 리턴 기능&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;과 같습니다. Multi-Thread가 지원되지 않고, 호출시&amp;nbsp;Block됩니다.&lt;br /&gt;
그러니, UI에서 호출할 때에는 caller에서 Thread를 만들어 내부에서 사용하세요.&lt;br /&gt;
&lt;br /&gt;리턴값과 NULL을 체크하지 않는 Rough한 사용예는 다음과 같습니다.&lt;br /&gt;
&lt;br /&gt;&lt;TEXTAREA class=c++ name=code&gt;#include &quot;HttpClient.h&quot;
...
LPBYTE		bufResponse		= NULL;
LPTSTR		lpszResponse	= NULL;
DWORD		dwCbResponse	= 0;
DWORD		dwHttpCode		= 0;
CHttpClient	c;

c.SetEncoding(CP_UTF8);
c.CreateSession(TEXT(&quot;myagnt&quot;), TEXT(&quot;localhost&quot;), 80);
c.AddPostParam(TEXT(&quot;abcdef&quot;), TEXT(&quot;좋습니다,좋구요&quot;));
c.AddPostFile(TEXT(&quot;file&quot;), TEXT(&quot;test.txt&quot;), TEXT(&quot;e:\\data\\qqq.txt&quot;));
c.RequestPost(TEXT(&quot;/tmp/upload.php?arg=1&amp;amp;arg2=good&quot;), &amp;amp;bufResponse, &amp;amp;dwCbResponse, &amp;amp;lpszResponse, &amp;amp;dwHttpCode);
AfxMessageBox(lpszResponse);
c.FreeAlloc(bufResponse);
c.FreeAlloc(lpszResponse);
c.CloseSession();&lt;/TEXTAREA&gt;&lt;br /&gt;
&lt;br /&gt;그리고, http://localhost/tmp/upload.php는 다음과 같습니다.&lt;br /&gt;
&lt;TEXTAREA class=php name=code&gt;&amp;lt;?php 
$uploaddir = '/home/greenfish/upload/'; 
$uploadfile = $uploaddir . basename($_FILES['file']['name']); 

echo '&amp;lt;pre&amp;gt;'; 
if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile))
{ 
    echo &quot;File is valid, and was successfully uploaded.\n&quot;; 
}
else
{ 
    echo &quot;Possible file upload attack!\n&quot;; 
} 

echo $_POST['abcdef'];

echo 'Here is some more debugging info:'; 
print_r($_FILES); 

print_r($_POST);
print_r($_GET);

print &quot;&amp;lt;/pre&amp;gt;&quot;; 

?&amp;gt; 
&lt;/TEXTAREA&gt;&lt;br /&gt;
&lt;br /&gt;그럼 아래와 같이 AfxMessageBox됩니다.&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile22.uf.tistory.com/original/110D5D494E9BDF6130163D&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile22.uf.tistory.com/image/110D5D494E9BDF6130163D&quot; alt=&quot;&quot; filemime=&quot;image/jpeg&quot; filename=&quot;001.png&quot; height=&quot;429&quot; width=&quot;428&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;즉, 파일이 업로드 되었고, HTTP Post/Get Data가 동시에 잘 전달되었음이 확인됩니다.&lt;br /&gt;
&lt;br /&gt;자세한건, 위 예를 보시기 바라며,&lt;br /&gt;
RequestPost 함수는 해당 함수 구현부의 주석을 참고 바랍니다.&lt;/P&gt;&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-111-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-111-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=21534043&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/111&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/프로그래밍&quot;&gt;프로그래밍&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/프로그래밍/Win32&quot;&gt;Win32&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/113&quot; &gt;&amp;quot;이 프로그램이 제대로 설치되지 않았을 수 있습니다.&amp;quot; 대처 빌드 방법&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/11/24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/112&quot; &gt;VC9.0 + MFC + StaticLink 시, gdiplus.dll 오류 해결법&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/11/17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/111&quot; &gt;WinInet으로 HTTP POST File Upload와 Data를 함께 보내기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/10/17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/98&quot; &gt;Internet Explorer_Hidden 윈도우 보호하기 (IE Web Control Message Hooking)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/08/20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/87&quot; &gt;DLL의 메모리릭을 쉽게 찾아 보기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/04/25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/84&quot; &gt;.exe의 export 함수를 이용한 개발 방법론 (공통함수 처리, 효율적인 Third-party plug-in 구조)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/03/31&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>Win32</category>
			<category>boundary</category>
			<category>HttpAddRequestHeaders</category>
			<category>HttpEndRequest</category>
			<category>HttpOpenRequest</category>
			<category>HttpQueryInfo</category>
			<category>HttpSendRequestEx</category>
			<category>HTTP_QUERY_CONTENT_LENGTH</category>
			<category>HTTP_QUERY_STATUS_CODE</category>
			<category>InternetAttemptConnect</category>
			<category>InternetConnect</category>
			<category>InternetOpen</category>
			<category>Multi-Part</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/111</guid>
			<comments>http://greenfishblog.tistory.com/111#entry111comment</comments>
			<pubDate>Mon, 17 Oct 2011 16:59:48 +0900</pubDate>
		</item>
		<item>
			<title>concat과 printf를 동시에 수행하는 함수 공유</title>
			<link>http://greenfishblog.tistory.com/110</link>
			<description>&lt;textarea name=&quot;code&quot; class=&quot;c++&quot;&gt;DWORDStringCbVPrintfAppendA(OUT LPSTR lpszDestA, IN DWORD dwCbSize, IN INT nStartPos, OUT PINT pnEndPos, IN LPCSTR lpszFormatA, ...)
{
	DWORD	dwRtnValue	= ERROR_SUCCESS;
	HRESULT	hResult		= S_OK;
	va_list arg			= {0,};

	if ((NULL == lpszDestA) || (NULL == pnEndPos) || (NULL == lpszFormatA))
	{
		dwRtnValue = ERROR_INVALID_PARAMETER;
		assert(FALSE);
		goto FINAL;
	}

	if (nStartPos + 1 &amp;gt;= dwCbSize)
	{
		dwRtnValue = ERROR_MORE_DATA;
		assert(FALSE);
		goto FINAL;
	}

	va_start(arg, lpszFormatA);

	hResult = StringCchVPrintfA(&amp;amp;lpszDestA[nStartPos], dwCbSize - nStartPos, lpszFormatA, arg);
	if (S_OK == hResult)
	{
		dwRtnValue = ERROR_SUCCESS;
	}
	else
	{
		if (STRSAFE_E_INVALID_PARAMETER == hResult)
		{
			dwRtnValue = ERROR_INVALID_PARAMETER;
		}
		else if (STRSAFE_E_INSUFFICIENT_BUFFER == hResult)
		{
			dwRtnValue = ERROR_MORE_DATA;
		}
		else
		{
			dwRtnValue = ERROR_INTERNAL_ERROR;
		}

		// 실패했다면, 다시 지움.
		lpszDestA[nStartPos] = TEXT('\0');
	}

	*pnEndPos = strlen(&amp;amp;lpszDestA[nStartPos]) + nStartPos;

FINAL:
	return dwRtnValue;
}
&lt;/textarea&gt;
&lt;br /&gt;
&lt;br /&gt;위 함수는 하나의 buffer에 printf를 concat하면서 진행합니다.&lt;br /&gt;
strsafe 함수군을 사용하므로, #include &amp;lt;strsafe.h&amp;gt;를 include 선언 마지막에 추가해야 합니다.&lt;br /&gt;
(ANSI 전용 함수만 공유합니다. StringCchPrintf와 _tcslen으로 변경하면, TCHAR 사용 가능합니다.)&lt;br /&gt;
&lt;br /&gt;파라미터 설명보다 아래 사용예를 보시는것이 편합니다.&lt;br /&gt;
&lt;br /&gt;막 사용한 예)&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
CHAR sz[35] = {0,};&lt;br /&gt;
INT nPos = 0;&lt;br /&gt;
StringCbVPrintfAppendA(sz, 35, nPos, &amp;amp;nPos, &quot;__%s, %d__&quot;, &quot;abc&quot;, 555);&lt;/div&gt;
&lt;div&gt;StringCbVPrintfAppendA(sz, 35, nPos, &amp;amp;nPos, &quot;****%s, %d****&quot;, &quot;abc&quot;, 1111);&lt;/div&gt;
&lt;div&gt;StringCbVPrintfAppendA(sz, 35, nPos, &amp;amp;nPos, &quot;@%s, %d@&quot;, &quot;qwerty&quot;, 1231);&lt;/div&gt;
&lt;div&gt;StringCbVPrintfAppendA(sz, 35, nPos, &amp;amp;nPos, &quot;@%s, %d@&quot;, &quot;qwerty&quot;, 1231);&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
가 되면,&lt;br /&gt;
&lt;br /&gt;__abc,555__ ==&amp;gt; __abc,555__***abc, 1111**** =&amp;gt;&amp;nbsp;__abc,555__***abc, 1111**** =&amp;gt;&amp;nbsp;__abc,555__***abc, 1111****&lt;br /&gt;
와 같이 sz값이 변경됩니다.&lt;br /&gt;
즉, 넘치게 되면 추가되지 않습니다.&lt;br /&gt;
&lt;br /&gt;리턴값이 ERROR_SUCCESS 이면 제대로 성공한 것이고,&lt;br /&gt;
위와 같이 버퍼가 모자란 경우에는 ERROR_MORE_DATA가 리턴됩니다.&lt;br /&gt;
해당값이 리턴되면, 버퍼의 크기를 늘려서 다시 호출하면 됩니다. :)&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-110-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-110-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=21457434&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/110&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/프로그래밍&quot;&gt;프로그래밍&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/프로그래밍/Let%27s%20Share%20it&quot;&gt;Let's Share it&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/115&quot; &gt;비동기(OVERLAPPED I/O, IOCP, Thread Pool) IPC PIPE Class 공유&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/12/14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/114&quot; &gt;[ATL/MFC/C++] Ini Parser(ini 파서)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/11/30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/110&quot; &gt;concat과 printf를 동시에 수행하는 함수 공유&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/10/14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/94&quot; &gt;Window Event Log(윈도우 이벤트 로그) 읽기&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/07/20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/85&quot; &gt;Proxy 서버 구하기 (자동 구성 스크립트, pac)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/04/04&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/83&quot; &gt;Windows 확장자 등록 Helper 함수 공유&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/03/31&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>Let's Share it</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/110</guid>
			<comments>http://greenfishblog.tistory.com/110#entry110comment</comments>
			<pubDate>Fri, 14 Oct 2011 16:08:22 +0900</pubDate>
		</item>
		<item>
			<title>[mongodb] Sharding</title>
			<link>http://greenfishblog.tistory.com/109</link>
			<description>&lt;P&gt;sharding은 mongodb의 scaling out을 제공한다.&lt;br /&gt;
sharding은 db를 사용하는 application의 영향없이,&lt;br /&gt;
load와 data size 증가 처리를 도와준다.&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-SIZE: 11pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;* sharding 소개&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;br /&gt;
&lt;br /&gt;sharding은 서로 다른 machine에 data를&lt;br /&gt;
쪼개고(splitting) 다른 부분들을 저장하는 process를 말한다.&lt;br /&gt;
partitioning 용어도 쓰이기도 한다.&lt;br /&gt;
machine들간에 data를 쪼개는것에 의해,&lt;br /&gt;
성능 좋고 대용량의 machine 없이도 더 많은 data와 그 처리를 가능토록 한다.&lt;/P&gt;
&lt;P&gt;수동(manual) sharding은 대부분의 db software에서 제공된다.&lt;br /&gt;
application에서 몇개의 다른 server로 접속을 관리할 때,&lt;br /&gt;
각각은 서로 독립적으로 된다. application은 다른 server에 다른 data를&lt;br /&gt;
저장하도록 하며, 적합한 server에 data를 구하도록 query한다.&lt;br /&gt;
이러한 application은 잘 동작하지만, cluster를 추가/삭제하는데&lt;br /&gt;
어렵고, load 패턴이나 data의 분산정도가 변경될때도 마찬가지 이다.&lt;/P&gt;
&lt;P&gt;mongodb는 autosharding을 지원하는데, 이는,&lt;br /&gt;
관리가 어려웠던 수동 sharding의 고통을 제거한다.&lt;br /&gt;
cluster는 data를 쪼개는 작업을 처리하고, 자동으로 re-balancing 한다.&lt;br /&gt;
이제부터 sharding와 autosharding은 같은 뜻으로 고려한다.&lt;br /&gt;
물론 manual sharding과는 차이가 있다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;* mongodb의 autosharding&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;mongodb autosharding의 기본 개념은 collection을 더작은 chunk로 나누는&lt;br /&gt;
것이다. 이러한 chunk들은 shard들을 경유해 분배되는데, 이는 각각의 shard가&lt;br /&gt;
total data set의 부분 집합으로 책임을 지기 위해서이다. 우리는 어떤 shard가&lt;br /&gt;
어떤 data를 가지고 있는지, 혹은 data가 다수의 shard에 어떻게 쪼개졌는지&lt;br /&gt;
알고 싶지는 않다. 그래서 shard에 앞서 mongos라고 불리는 routing process를&lt;br /&gt;
실행시키는 것이다. 이러한 routerr는 모든 data의 위치를 알고 있으며,&lt;br /&gt;
application은 그것에 접소하고 일반적인 request를 수행한다. application에서&lt;br /&gt;
알기로는, 일반 mongod에 connect된다. router는 어떤 data가 어떤 shard에 있는지를&lt;br /&gt;
알고 있고, 그래서 적합한 shard들에 request를 전송한다. 만일 request에 응답이 있다면,&lt;br /&gt;
router는 그들을 수집하고 application에 전달한다.&lt;/P&gt;
&lt;P&gt;nonshard mongodb는 아래와 같이 client는 mongod process에 접속한다.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;client &amp;lt;--&amp;gt; mongod&lt;/P&gt;
&lt;P&gt;shard된 경우는 아래와 같이 mongos process에 접속한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;client &amp;lt;--&amp;gt; mongos &amp;lt;---&amp;gt; mongod&lt;br /&gt;
&lt;FONT color=#ffffff&gt;client &amp;lt;--&amp;gt; mongos &amp;lt;-&lt;/FONT&gt;|&lt;br /&gt;
&lt;FONT color=#ffffff&gt;client &amp;lt;--&amp;gt; mongos &amp;lt;-&lt;/FONT&gt;|-&amp;gt; mongod&lt;br /&gt;
&lt;FONT color=#ffffff&gt;client &amp;lt;--&amp;gt; mongos &amp;lt;-&lt;/FONT&gt;|&lt;br /&gt;
&lt;FONT color=#ffffff&gt;client &amp;lt;--&amp;gt; mongos &amp;lt;-&lt;/FONT&gt;--&amp;gt; mongod&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;shard는 언제?&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&quot;언제 sharding을 시작해야 하는가?&quot;로 종종 질문을 받는다.&lt;br /&gt;
&quot;sharding이 좋은 생각이다~!&quot;라는 징조는 다음과 같다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;- 현재 machine에 disk space가 떨어졌을 때&lt;br /&gt;
- 단일 mongod가 처리할 수 있는 속도보다 빨리 data를 쓰고 싶을 때&lt;br /&gt;
- 성능 향상을 위해 memory에 있는 data의 크기를 키우고 싶을 때&lt;/P&gt;
&lt;P&gt;일반적으로, nonshard로 시작하고, 필요시 그것을 shard로 변경한다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;* sharding의 key&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;sharding이 이뤄졌다면, collection으로 부터 key를 선택해야 하며,&lt;br /&gt;
그 값으로 data를 쪼개게 된다. 이러한 key를 shard key라 한다.&lt;/P&gt;
&lt;P&gt;예를 들어 보자.&lt;br /&gt;
people을 표현하는 document의 collection이 있다고 가정하자.&lt;br /&gt;
shard key로 name을 선택했다면, 하나의 shard는 A~F까지로 시작하는 &quot;name&quot;을&lt;br /&gt;
가지고 있을 것이다. 물론 그다음 shard는 G~P일 것이고, 마지막으로 Q~Z일 것이다.&lt;br /&gt;
만일 shard를 추가(혹은 삭제)했을 때, mongodb는 이러한 data를 기반으로 re-balance를&lt;br /&gt;
실행하도록 한다.&lt;br /&gt;
(만일 traffic이 높은 임의의 shard는, 덜 사용되는 다른 shard보다 더 작은양의 data가 들어갈 것이다)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;기존 collection의 sharding&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;기존에 있는 log 용도의 collection이 있고, 그것을 sharding해 보자.&lt;br /&gt;
만일, shard key로 &quot;timestamp&quot;를 사용한다면, 모든 data에 대해 단일 shard로 구성된다.&lt;br /&gt;
어떤 data를 insert하면, mongodb는 하나의 shard로 할 것이다.&lt;/P&gt;
&lt;P&gt;이제, 새로운 shard를 추가한다고 가정하자.&lt;br /&gt;
추가된 shard가 이제 동작중이라면, mongodb는 2개의 chunk로 collection을 쪼갠다.&lt;br /&gt;
chunk는 shard key에 대한 값의 범위에 대한 정보를 가지고 있다.&lt;br /&gt;
그리고, -무한대~2003/07/26, 그리고 2003/07/27~+무한대와 같이 timestamp기준으로&lt;br /&gt;
쪼개진다. 이러한 chunk들중 하나는 다른 shard로 옮겨갈 것이다.&lt;/P&gt;
&lt;P&gt;2003/07/27 이전의 timestamp를 가지는 document가 추가되면,&lt;br /&gt;
첫 chunk에 추가된다. 그렇지 않다면 두번째 chunk에 저장된다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;자연 증가(incrementing) shard key vs. 랜덤 shard key&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;end user 입장에서 shard 설치는 nonshard된 것과 구별이 되어서는 안된다.&lt;br /&gt;
그러나, shard key가 선택되었느냐에 따라 query가 다르다는것을 이해하면,&lt;br /&gt;
유용할 때가 만다.&lt;/P&gt;
&lt;P&gt;앞서, &quot;name&quot; key에 대해 shard된 경우를 예를 들어 보자. 물론, 3개의 shard이다.&lt;/P&gt;
&lt;P&gt;db.people.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;find&lt;/FONT&gt;&lt;/STRONG&gt;({&quot;name&quot;:&quot;Susan&quot;})&lt;br /&gt;
; mongos는 바로 Q-Z shard에 query할 것이다. 해당 shard로 부터 수신되면 client에 보낸다.&lt;/P&gt;
&lt;P&gt;db.people.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;find&lt;/FONT&gt;&lt;/STRONG&gt;({&quot;name&quot;:{&quot;$lt&quot;:&quot;L&quot;}})&lt;br /&gt;
; mongos는 A-F, G-P shard들에게 연속으로 query한다. 그들의 응답으로 client에 보낸다.&lt;/P&gt;
&lt;P&gt;db.people.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;find&lt;/FONT&gt;&lt;/STRONG&gt;().sort({&quot;email&quot;:1})&lt;br /&gt;
; mongos는 모든 shard에 대해 query하고, 그 결과를 merge sort한다.&lt;br /&gt;
mongos는 각 server로 부터의 받은 cursor를 사용하며, 그래서 전체 dataset을 구할&lt;br /&gt;
필요는 없다.&lt;/P&gt;
&lt;P&gt;db.people.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;find&lt;/FONT&gt;&lt;/STRONG&gt;({&quot;email&quot;:&quot;&lt;A href=&quot;mailto:joe@example.com&quot;&gt;joe@example.com&lt;/A&gt;&quot;})&lt;br /&gt;
; mongos는 email key의 발자취를 가지고 있지 않다. 그래서,&lt;br /&gt;
어떤 shard가 보내져야 하는지를 모른다. 그래서 연속으로 모든 shard에 query를 보낸다.&lt;/P&gt;
&lt;P&gt;만일, 새로운 document가 insert된다면, mongos는 적당한 shard로 &quot;name&quot; key의 값을 기반으로&lt;br /&gt;
보낸다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;sharding 세팅하기&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;크게 다음과 같이 2개의 과정을 거친다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;- server 시작하기&lt;br /&gt;
- data를 어떻게 shard할지 결정&lt;/P&gt;
&lt;P&gt;sharding은 기본으로 다음의 서로 다른 component들이 함께 작업을 진행한다.&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;shard&lt;/FONT&gt;&lt;br /&gt;
; collection data의 부분 집합을 가지는 container.&lt;br /&gt;
shard는 단일 mongod server 혹은 replica set이다.&lt;br /&gt;
따라서, shard에 많은 server가 있더라도 master가 하나라면 모든 server는 동일 data를 가진다.&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;mongos&lt;/FONT&gt;&lt;br /&gt;
; router process이다. 기본적으로 request를 route시킨다. 그리고 결과를 종합한다.&lt;br /&gt;
그리고 어떠한 data나 설정 정보를 저장하지 않는다.&lt;br /&gt;
(config server로 부터 정보를 cache는 한다)&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;config server&lt;/FONT&gt;&lt;br /&gt;
; cluster 설정을 저장하는 server이다.&lt;br /&gt;
설정이란, 어떤 shard에 어떤 data를 저장하냐? 이다.&lt;br /&gt;
mongos는 영구적으로 저장하지 않기 때문에, shard 정보를 가져오기 위해서 필요했다.&lt;br /&gt;
config server로 부터 data를 동기화한다.&lt;/P&gt;
&lt;P&gt;이미 mongodb 작업을 하고 있었다면, shard를 준비할 수 있다.&lt;br /&gt;
(현재의 mongod는 당신의 첫 shard일 것이다)&lt;br /&gt;
다음은 부담없이 새로운 shard를 생성하는 과정을 보여준다.&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;server 시작하기&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;처음으로 config와 mongos server를 시작해야 한다.&lt;br /&gt;
config server가 먼저 시작되어야 한다.&lt;br /&gt;
config server는 다음과 같이 mongod와 비슷한 방식으로 시작할 수 있다.&lt;/P&gt;
&lt;P&gt;$ &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;mkdir&lt;/STRONG&gt; &lt;/FONT&gt;-p ~/dbs/config&lt;br /&gt;
$ &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;mongod&lt;/STRONG&gt; &lt;/FONT&gt;--dbpath ~/dbs/config --port 20000&lt;/P&gt;
&lt;P&gt;config server는 많은 disk space나 시스템 자원을 필요하지는 않는다.&lt;br /&gt;
(대략 200MB의 실제 data당 1KB 정도의 크기를 예상할 수 있다.)&lt;/P&gt;
&lt;P&gt;이제 application에서 접속할 mongos process가 필요하다.&lt;br /&gt;
routing server는 data directory를 필요하지 않고, config server의 위치가&lt;br /&gt;
필요할 뿐이다.&lt;/P&gt;
&lt;P&gt;$ &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;mongos&lt;/STRONG&gt; &lt;/FONT&gt;--port 30000 &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;--configdb&lt;/STRONG&gt; &lt;/FONT&gt;localhost:20000&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;shard 추가하기&lt;/FONT&gt;&lt;br /&gt;
; shard는 mongod instance이다.(혹은 replica set)&lt;br /&gt;
$ mkdir -p ~/dbs/shard1&lt;br /&gt;
$ mongod --dbpath ~/dbs/shard1 --port 10000&lt;/P&gt;
&lt;P&gt;이제 mongos process에 접속하고 cluster에 shard를 추가한다.&lt;br /&gt;
mongos에 아래와 같이 shell로 접속한다.&lt;br /&gt;
$ mongo localhost:30000/admin&lt;/P&gt;
&lt;P&gt;db.runCommand({addshard:&quot;localhost:10000&quot;, allowLocal:true})&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;added&quot; : &quot;localhost:10000&quot;,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;ok&quot; : true&lt;br /&gt;
}&lt;/P&gt;
&lt;P&gt;allowLocal은 localhost에 shard가 동작하고 있는 경우에만 필요하다.&lt;br /&gt;
mongodb는 cluster를 local에 저장하는 것을 원하진 않는다.&lt;br /&gt;
만일 릴리즈를 할 경우에는, 반드시 shard를 다른 machine으로 해야 한다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;data sharding하기&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;mongodb는 저장된 data의 모든 조각을 분산하진 않는다.&lt;br /&gt;
명시적으로 database와 collection level로 sharding해야만 가능하다.&lt;/P&gt;
&lt;P&gt;다음과 같은 예를 고려해보자.&lt;br /&gt;
foo database의 &quot;_id&quot; key의 bar collection을 shard한다.&lt;br /&gt;
우선, foo에 대해 sharding 시키자.&lt;/P&gt;
&lt;P&gt;db.runCommand({&quot;enablesharding&quot;:&quot;foo&quot;})&lt;/P&gt;
&lt;P&gt;collection의 database sharding 결과는 각각의 다른 shard에 저장된다.&lt;/P&gt;
&lt;P&gt;일단 database level에서 sharding되었다면, shardcollection 명령으로&lt;br /&gt;
collection으로 shard할 수 있다.&lt;/P&gt;
&lt;P&gt;db.runCommand({&quot;shardcollection&quot;:&quot;foo.bar&quot;, &quot;key&quot;:{&quot;_id&quot;:1}})&lt;/P&gt;
&lt;P&gt;해당 collection은 &quot;_id&quot; key에 의해 shard된다.&lt;br /&gt;
data를 추가하게 되면, _id 값을 기반으로 자동으로 분산하게 된다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;* Production Configuration&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;만일 production으로 application을 이동할 경우, 보다 견고한 setup이 필요하다.&lt;br /&gt;
실패없이 sharding하기 위해서 다음이 필요하다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;- 다중 config server&lt;br /&gt;
- 다중 mongos server&lt;br /&gt;
- 각 shard 당 replica set&lt;br /&gt;
- w 세팅 ([mongodb] Replication으l w 참고)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;견고한 config&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;다중 config server는 간단하다.&lt;br /&gt;
만일 한개의 config server(개발용) 혹은 3개의 config server(production용)가 있다고 하자.&lt;/P&gt;
&lt;P&gt;다중 config server는 다 동일하다. 즉, 3번 실행하면 된다.&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;mkdir &lt;/STRONG&gt;&lt;/FONT&gt;-p ~/dbs/config1 ~/dbs/config2 ~/dbs/config3&lt;br /&gt;
&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;mongod&lt;/STRONG&gt; &lt;/FONT&gt;--dbpath ~/dbs/config1 --port 20001&lt;br /&gt;
&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;mongod&lt;/STRONG&gt; &lt;/FONT&gt;--dbpath ~/dbs/config2 --port 20002&lt;br /&gt;
&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;mongod&lt;/STRONG&gt; &lt;/FONT&gt;--dbpath ~/dbs/config3 --port 20003&lt;/P&gt;
&lt;P&gt;mongos를 시작할때는, 다음과 같다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;mongos&lt;/FONT&gt;&lt;/STRONG&gt; &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;--configdb&lt;/FONT&gt;&lt;/STRONG&gt; localhost:20001,localhost:20002,localhost:20003&lt;/P&gt;
&lt;P&gt;config server는 두단계 commit을 사용한다.&lt;br /&gt;
cluster configuration의 개별 복사본을 유지하는데,&lt;br /&gt;
일반적인 mongodb 비동기 복사를 사용하지 않는다.&lt;br /&gt;
이는 단일 configuration server가 down되면,&lt;br /&gt;
cluster의 configuration 정보는 read-only가 된다.&lt;br /&gt;
client는 read와 write가 되는데, config server가 복원될 때 까지&lt;br /&gt;
re-balance는 이뤄지지 못한다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;많은 수의 mongos&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;많은 mongos를 원하는 만큼 운영할 수 있다.&lt;br /&gt;
하나의 추천된 setup은 모든 application server에 대해 mongos process를&lt;br /&gt;
실행시키는 것이다. 이는, 각각의 application server는 local의 mongos에&lt;br /&gt;
접근할 수 있으며, 그리고 만일 해당 server가 down 되더라도 그곳에 없는&lt;br /&gt;
mongos에 접근을 시도할자는 없을 것이다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;견고한 shard&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;production에서, 각 shard는 replica set으로 될 것이다.&lt;br /&gt;
이는 개별 server는 실패될 수 있으나, 전체 shard를 down 시키지는 않는다는 것이다.&lt;br /&gt;
shard로서 replica set을 추가할 때, 이름을 전달하고 addshard 명령을 사용한다.&lt;/P&gt;
&lt;P&gt;db.runCommand({&quot;addshard&quot;:&quot;foo/prod.example.com:27017&quot;})&lt;/P&gt;
&lt;P&gt;만일, prod.example.com이 down된다면, mongos는 replica set에 연결되었음을 아고&lt;br /&gt;
새로운 primary를 이용하도록 한다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;물리적 server&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;아래는 압도할 만한 machine 수가 된다:&lt;br /&gt;
3개의 config server, shard당 최소 2개의 mongod, 많은 mongos process....&lt;br /&gt;
그러나, 모든 것이 고유의 machine을 가지고 있진 않다.&lt;br /&gt;
피해야할 사항중 하나가 하나의 machine으로 전체 component를 구성하는 일이다.&lt;br /&gt;
예를들어, 3개의 config server 혹은 mongos process 혹은 전체 replica set을&lt;br /&gt;
하나의 machine에 구성하는 일이다.&lt;br /&gt;
그러나, config server와 mongos process는 replica set의 member와 함게 공유 가능하다.&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;* sharding 관리하기&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;sharding 정보는 config database에 대부분 저장된다.&lt;br /&gt;
이는 mongos process에 접속된것으로 부터 접근된다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;config collections&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;다음 부터의 모든 code는 mongos process에 shell로 접속한 경우이며,&lt;br /&gt;
use config를 이미 마친 것으로 가정한다.&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;shards&lt;/FONT&gt;&lt;br /&gt;
; shard list를 구할 수 있다.&lt;br /&gt;
db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;shards&lt;/FONT&gt;&lt;/STRONG&gt;.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;find&lt;/FONT&gt;&lt;/STRONG&gt;()&lt;br /&gt;
{ &quot;_id&quot; : &quot;shard0&quot;, &quot;host&quot; : &quot;localhosst:10000&quot; }&lt;br /&gt;
{ &quot;_id&quot; : &quot;shard1&quot;, &quot;host&quot; : &quot;localhosst:10001&quot; }&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;databases&lt;/FONT&gt;&lt;br /&gt;
; shard에 존재하는 database list와 정보를 구한다.&lt;/P&gt;
&lt;P&gt;db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;databases&lt;/FONT&gt;&lt;/STRONG&gt;.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;find&lt;/FONT&gt;&lt;/STRONG&gt;()&lt;br /&gt;
{ &quot;_id&quot; : &quot;admin&quot;, &quot;partitioned&quot; : false, &quot;primary&quot; : &quot;config&quot; }&lt;br /&gt;
{ &quot;_id&quot; : &quot;foo&quot;, &quot;partitioned&quot; : false, &quot;primary&quot; : &quot;shard1&quot; }&lt;br /&gt;
{ &quot;_id&quot; : &quot;x&quot;, &quot;partitioned&quot; : false, &quot;primary&quot; : &quot;shard0&quot; }&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;_id&quot; : &quot;test&quot;,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;partitioned&quot; : true,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;primary&quot; : &quot;shard0&quot;,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;sharded&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;test.foo&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;key&quot; : {&quot;x&quot; : 1},&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;unique&quot; : false&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
}&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&quot;_id&quot; : string&lt;br /&gt;
&amp;nbsp;; database의 이름&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&quot;partitioned&quot; : boolean&lt;br /&gt;
&amp;nbsp;; enablesharding이 실행된 상태일때 true&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&quot;primary&quot; : string&lt;br /&gt;
&amp;nbsp;; shard &quot;_id&quot;에 해당된다.&lt;/P&gt;
&lt;P&gt;chunks&lt;br /&gt;
; chunk 정보는 chunks collection에 저장된다.&lt;br /&gt;
data가 cluster 상에 어떻게 쪼개졌는지 보여준다.&lt;/P&gt;
&lt;P&gt;db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;chunks&lt;/FONT&gt;&lt;/STRONG&gt;.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;find&lt;/FONT&gt;&lt;/STRONG&gt;()&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;_id&quot; : &quot;test.foo-x_MinKey&quot;,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;lastmod&quot; : { &quot;t&quot; : 1276636243000, &quot;i&quot; : 1 },&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;ns&quot; : &quot;test.foo&quot;,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;min&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;x&quot; : { $minKey : 1 }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; },&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;max&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;x&quot; : { $maxKey : 1 }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; },&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;shard&quot; : &quot;shard0&quot;&lt;br /&gt;
}&lt;/P&gt;
&lt;P&gt;chunk range는 -무한대(MinKey)에서 +무한대(MaxKey)가 된다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;sharding 명령&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;summary 구하기&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;printShardingStatus는 이전 collection의 quick summary를 제공한다.&lt;/P&gt;
&lt;P&gt;db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;printShardingStatus&lt;/FONT&gt;&lt;/STRONG&gt;()&lt;/P&gt;
&lt;P&gt;--- Sharding Status ---&lt;br /&gt;
&amp;nbsp; sharding version: { &quot;_id&quot; : 1, &quot;version&quot; : 3 }&lt;br /&gt;
&amp;nbsp; shards:&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &quot;_id&quot; : &quot;shard0&quot;, &quot;host&quot; : &quot;localhost:10000&quot; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &quot;_id&quot; : &quot;shard1&quot;, &quot;host&quot; : &quot;localhost:10001&quot; }&lt;br /&gt;
&amp;nbsp; databases:&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &quot;_id&quot; : &quot;admin&quot;, &quot;partitioned&quot; : false, &quot;primary&quot; : &quot;config&quot; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &quot;_id&quot; : &quot;foo&quot;, &quot;partitioned&quot; : false, &quot;primary&quot; : &quot;shard1&quot; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &quot;_id&quot; : &quot;x&quot;, &quot;partitioned&quot; : false, &quot;primary&quot; : &quot;shard0&quot; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &quot;_id&quot; : &quot;test&quot;, &quot;partitioned&quot; : true, &quot;primary&quot; : &quot;shard0&quot;,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;sharded&quot; : { &quot;test.foo&quot; : { &quot;key&quot; : { &quot;x&quot; : 1 }, &quot;unique&quot; : false } } }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; test.foo chunks:&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &quot;x&quot; : { $minKey : 1 } } --&amp;gt;&amp;gt; { &quot;x&quot; : { $maxKey : 1 } } on : shard0&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &quot;t&quot; : 1276636243000, &quot;i&quot; : 1 }&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;shard 제거하기&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;db.runCommand({&quot;removeshard&quot; : &quot;localhost:10000&quot;});&lt;br /&gt;
와 같이 한다.&lt;/P&gt;&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-109-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-109-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=21176457&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/109&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/Research&quot;&gt;Research&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/Research/mongodb&quot;&gt;mongodb&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/109&quot; &gt;[mongodb] Sharding&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/10/06&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/108&quot; &gt;[mongodb] Replication&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/107&quot; &gt;[mongodb] Administration&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/106&quot; &gt;[mongodb] Advanced topics&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/105&quot; &gt;[mongodb] Aggregation (MapReduce)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/104&quot; &gt;[mongodb] Indexing&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/22&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>mongodb</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/109</guid>
			<comments>http://greenfishblog.tistory.com/109#entry109comment</comments>
			<pubDate>Thu, 06 Oct 2011 11:15:56 +0900</pubDate>
		</item>
		<item>
			<title>[mongodb] Replication</title>
			<link>http://greenfishblog.tistory.com/108</link>
			<description>&lt;P&gt;mongodb administrator의 가장 중요한 작업중 하나다.&lt;br /&gt;
replication(복사)을 구성하고 동작시키는 것이다.&lt;/P&gt;
&lt;P&gt;replica(복제노드)는 장애 극복, data integrity(입력된 데이터가 변경/파괴되지 않은 상태),&lt;br /&gt;
에서 더 나아가,&lt;br /&gt;
확장성을 가지고 읽기(scaling-out read), data source의 offline batch 작업등등...&lt;br /&gt;
을 지원하는데 사용된다.&lt;/P&gt;
&lt;P&gt;master - slave replication&lt;/P&gt;
&lt;P&gt;master&lt;br /&gt;
|&lt;br /&gt;
|- slave&lt;br /&gt;
|&lt;br /&gt;
|- slave&lt;br /&gt;
|&lt;br /&gt;
|- slave&lt;br /&gt;
|&lt;br /&gt;
...&lt;/P&gt;
&lt;P&gt;&lt;br /&gt;
가장 일반적인 방식이다.&lt;br /&gt;
flexible하고 backup에 적합하다.&lt;br /&gt;
그리고 그외 장애극복 및 read scaling(규모의 read)등등이다.&lt;/P&gt;
&lt;P&gt;기본적인 세팅은 master node와 하나 이상의 slave node를 시작하는 것이다.&lt;br /&gt;
각각은 master의 address를 알아야 한다.&lt;/P&gt;
&lt;P&gt;master로 시작하고 싶으면 mongod --master로 한다.&lt;br /&gt;
slave로 시작하고 싶으면 mongod --slave -source master_address로 한다.&lt;br /&gt;
master_address는 master node의 주소로, 막 시작되었어야 한다.&lt;/P&gt;
&lt;P&gt;이러한 세팅을 하나의 machine으로 구성하기도 쉽다.&lt;br /&gt;
우선, master가 저장할 directory를 구성하고 prot 10000으로 세팅한다.&lt;br /&gt;
$ &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;mkdir&lt;/STRONG&gt;&lt;/FONT&gt; -p ~/dbs/master&lt;br /&gt;
$ &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;mongod&lt;/FONT&gt;&lt;/STRONG&gt; &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;--dbpath&lt;/STRONG&gt; &lt;/FONT&gt;~/dbs/master &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;--port&lt;/STRONG&gt; &lt;/FONT&gt;10000 &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;--master&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;이제 slave를 세팅할 차례인데, 다은 경로와 port를 만든다.&lt;/P&gt;
&lt;P&gt;$ &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;mkdir&lt;/STRONG&gt; &lt;/FONT&gt;-p ~/dbs/slave&lt;br /&gt;
$ &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;mongod &lt;/FONT&gt;&lt;FONT color=#ff8b16&gt;-dbpath&lt;/FONT&gt;&lt;/STRONG&gt;&lt;FONT color=#ff8b16&gt; &lt;/FONT&gt;~/dbs/slave &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;--port&lt;/STRONG&gt; &lt;/FONT&gt;10001 &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;--slave --source&lt;/STRONG&gt; &lt;/FONT&gt;localhost:10000&lt;/P&gt;
&lt;P&gt;모든 slave는 master node로 부터 복사되어야 한다.&lt;br /&gt;
현재로서는 slave로 부터 복사하는 machinism이 없는데,&lt;br /&gt;
slave는 그들 고유의 oplog가 없기 때문이다.&lt;/P&gt;
&lt;P&gt;slave cluster의 숫자 제한은 없으나, 수천의 slave를 가지고 단일 master에 query하는&lt;br /&gt;
것은 처리 능력을 압도해 버리므로 좋지 않다.&lt;br /&gt;
현실적으로 12개 이하 정도의 slave 수는 동작을 잘 한다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;FONT color=#ff8b16&gt;Options&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;--only&lt;br /&gt;
; slave node로 하여금 single database만 복사하도록 한다. (기본은 all)&lt;/P&gt;
&lt;P&gt;--slavedelay&lt;br /&gt;
; master로 부터 operation 적용에 대해 delay한다(몇 초).&lt;br /&gt;
이는 사용자가 부주의로 delete/insert 하는 사고를 쉽게 대처해 준다.&lt;/P&gt;
&lt;P&gt;--fastsync&lt;br /&gt;
; master node의 snapshot으로 부터 시작한다.&lt;br /&gt;
fullsync보다 빠르기 때문에, 시작시간을 빠르게한다.&lt;/P&gt;
&lt;P&gt;--autoresync&lt;br /&gt;
; slave가 master로 sync를 피할때, funnsync를 자동으로 수행한다.&lt;/P&gt;
&lt;P&gt;--oplogsize&lt;br /&gt;
; master의 oplog 크기를 설정한다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;Source 추가/삭제하기&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;localhost:27017에서 master가 동작중일떄,&lt;br /&gt;
&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;mongod --slave --dbpath &lt;/FONT&gt;&lt;/STRONG&gt;~/dbs/slave &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;--port&lt;/STRONG&gt; &lt;/FONT&gt;27018&lt;br /&gt;
을 통해 slave를 시작 할 수 있다.&lt;br /&gt;
물론 아래와 같이 shell에서도 지정할 수 있다.&lt;br /&gt;
&lt;br /&gt;만일 master가 localhost:10000이라면, &lt;br /&gt;
그러면,&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;use&lt;/FONT&gt;&lt;/STRONG&gt; local&lt;br /&gt;
db.source.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;insert&lt;/FONT&gt;&lt;/STRONG&gt;({&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;host&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:&quot;localhost:27017&quot;})&lt;/P&gt;
&lt;P&gt;을 통해 slave를 위한 source를 추가하였다.&lt;/P&gt;
&lt;P&gt;slave의 log를 보고싶다면, localhost:27017에 sync하여 가능하다.&lt;/P&gt;
&lt;P&gt;만일 localhost:10000이 master이고 localhost:10001이 slave라면,&lt;/P&gt;
&lt;P&gt;$ &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;mongo&lt;/FONT&gt;&lt;/STRONG&gt; localhost:10001&lt;br /&gt;
MongoDB shell version: 1.8.3&lt;br /&gt;
connecting to: localhost:10001/test&lt;br /&gt;
&amp;gt; &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;use&lt;/STRONG&gt; &lt;/FONT&gt;local&lt;br /&gt;
switched to db local&lt;br /&gt;
&amp;gt; db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;sources&lt;/FONT&gt;&lt;/STRONG&gt;.find()&lt;br /&gt;
{ &quot;_id&quot; : ObjectId(&quot;4e80007a0bdf33fb1db0739a&quot;), &quot;host&quot; : &quot;localhost:10000&quot;, &quot;source&quot; : &quot;main&quot;, &quot;syncedTo&quot; : { &quot;t&quot; : 1317011581000, &quot;i&quot; : 1 }, &quot;localLogTs&quot; : { &quot;t&quot; : 0, &quot;i&quot; : 0 } }&lt;/P&gt;
&lt;P&gt;와 같다.&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;* Replica sets (복사본 집합)&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;repilica set은 기본적으로 자동으로 장애를 극복하는 master-slave cluster를 의미한다.&lt;br /&gt;
master-slave cluster와 replica set의 가장 큰 차이점은 replica set은 단일 master를 가지지&lt;br /&gt;
않는다는 점이다. cluster에 의해 하나가 선출(elected)되고, 만약 현재의 master가 down되면&lt;br /&gt;
다른 node로 변경하게 된다. 여하튼, 그러나 master-slave cluster와 replica set은 그 차이점은&lt;br /&gt;
별로 없다. replica set은 항상 단일 master node(primary)와 하나 이상의 slave(secondary)를 가지고 있다.&lt;/P&gt;
&lt;P&gt;만일, machine &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;(1)&lt;/STRONG&gt;&lt;/FONT&gt;, machine &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;(2)&lt;/FONT&gt;&lt;/STRONG&gt;가 있다고 가정하자.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;(1)&lt;/STRONG&gt;&lt;/FONT&gt; primary -&amp;gt; &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;(2)&lt;/FONT&gt;&lt;/STRONG&gt; secondary와 같이 두개의 구성원으로 이뤄진 replica set이 있다.&lt;br /&gt;
만일, &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;(1)&lt;/FONT&gt;&lt;/STRONG&gt;이 down되면, &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;(2)&lt;/FONT&gt;&lt;/STRONG&gt;가 master가 된다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;(1)&lt;/FONT&gt;&lt;/STRONG&gt; X &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;(2)&lt;/FONT&gt;&lt;/STRONG&gt; primary&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;그리고, &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;(1)&lt;/FONT&gt;&lt;/STRONG&gt;이 원상 복귀되면, 새 primary의 slave로 시작한다.&lt;br /&gt;
&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;(1)&lt;/FONT&gt;&lt;/STRONG&gt; secondary &amp;lt;- &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;(2)&lt;/FONT&gt;&lt;/STRONG&gt; primary&lt;/P&gt;
&lt;P&gt;replica set의 장점은 모든것이 자동화되어 있다는 점이다.&lt;br /&gt;
set 그 자체는 수많은 관리자 작업을 수행하고 slave를 자동으로 승격한다. 그리고,&lt;br /&gt;
coinsistency(불일치, 동일 object를 나타내는 2개의 data가 있을때, 한개만 변경)에&lt;br /&gt;
빠지지 않음을 확신시켜 준다.&lt;br /&gt;
개발자가 사용하기에 쉽게 되어 있다. set에 몇개의 server를 지명하고, driver에서 자동으로&lt;br /&gt;
모든 server를 계산하고, 현재 master가 die되면 자동으로 극복하는 것을 처리한다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;초기 set&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;replica set을 세팅하기 위해서, master-slave cluster 구성에서 조금더 나아가야 한다.&lt;br /&gt;
일단, 2개의 server로 세팅하는 것으로 시작하자.&lt;br /&gt;
우선, data directory를 다음과 같이 설정한다.&lt;br /&gt;
$ &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;mkdir -p&lt;/FONT&gt;&lt;/STRONG&gt; ~/dbs/node1 ~/dbs/node2&lt;/P&gt;
&lt;P&gt;시작하기전 결정해야 하는 사항이 있는데, 그것이 바로 replica set을 위한 이름이다.&lt;br /&gt;
우선 greenfishmongo라 하자.&lt;/P&gt;
&lt;P&gt;server를 시작했다면, 새로운 옵션으로 --replSet이 필요하다.&lt;/P&gt;
&lt;P&gt;$ &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;mongod&lt;/FONT&gt;&lt;/STRONG&gt; &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;--dbpath&lt;/STRONG&gt; &lt;/FONT&gt;~/dbs/node1&lt;STRONG&gt; &lt;FONT color=#ff8b16&gt;--port &lt;/FONT&gt;&lt;/STRONG&gt;10001 &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;--replSet&lt;/STRONG&gt; &lt;/FONT&gt;greenfishmongo/localhost:10002&lt;br /&gt;
$ &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;mongod&lt;/STRONG&gt; &lt;/FONT&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;--dbpath&lt;/STRONG&gt; &lt;/FONT&gt;~/dbs/node2&lt;STRONG&gt; &lt;FONT color=#ff8b16&gt;--port &lt;/FONT&gt;&lt;/STRONG&gt;10002 &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;--replSet&lt;/STRONG&gt; &lt;/FONT&gt;greenfishmongo/localhost:10001&lt;/P&gt;
&lt;P&gt;만일 3번째 server를 구축한다면, 아래 두개중 한개로 전달할 수 있다.&lt;br /&gt;
$ &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;mongod --dbpath &lt;/FONT&gt;&lt;/STRONG&gt;~/dbs/node3 &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;--port &lt;/FONT&gt;&lt;/STRONG&gt;10003 --replSet greenfishmongo/localhost:10001&lt;br /&gt;
$ &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;mongod --dbpath &lt;/FONT&gt;&lt;/STRONG&gt;~/dbs/node3 &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;--port &lt;/FONT&gt;&lt;/STRONG&gt;10003 --replSet greenfishmongo/localhost:10001,localhost:10002&lt;/P&gt;
&lt;P&gt;장점중 하나로 그들은 self-detecting하다. set에 한개를 추가한다면, mongodb는 나머지&lt;br /&gt;
node를 자동으로 connect한다.&lt;/P&gt;
&lt;P&gt;이와같이 server로 구성했다면 server log에서 replica set이 초기화되지 않았다는 부분이&lt;br /&gt;
발견된다. 이는 shell에서 초기화를 해줘야 해결된다.&lt;br /&gt;
([startReplSets] replSet info you may need to run replSetInitiate -- rs.initiate() in the shell -- if that is not already done)&lt;/P&gt;
&lt;P&gt;server중 하나를 shell에서 연결한다.&lt;/P&gt;
&lt;P&gt;$ &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;mongo&lt;/FONT&gt;&lt;/STRONG&gt; localhost:10001/admin&lt;br /&gt;
MongoDB shell version: 1.8.3&lt;br /&gt;
connecting to: localhost:10001/admin&lt;br /&gt;
&amp;gt; db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;runCommand&lt;/FONT&gt;&lt;/STRONG&gt;({&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;replSetInitiate&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:{&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&quot;_id&quot;:&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;greenfishmongo&lt;/FONT&gt;&lt;/STRONG&gt;&quot;,&lt;br /&gt;
&quot;members&quot;:[&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;_id&quot;:1,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;host&quot;:&quot;localhost:10001&quot;&lt;br /&gt;
},&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;_id&quot;:2,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;host&quot;:&quot;localhost:10002&quot;&lt;br /&gt;
}&lt;br /&gt;
]}})&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&quot;info&quot; : &quot;Config now saved locally.&amp;nbsp; Should come online in about a minute.&quot;,&lt;br /&gt;
&amp;nbsp;&quot;ok&quot; : 1&lt;br /&gt;
}&lt;br /&gt;
와 같이 진행된다.&lt;/P&gt;
&lt;P&gt;&quot;_id&quot;:&quot;greenfishmongo&quot;&lt;br /&gt;
; set 이름&lt;/P&gt;
&lt;P&gt;&quot;members&quot;:[...]&lt;br /&gt;
set에 있는 server member를 설정한다. 이후 추가할 수 있다.&lt;br /&gt;
각 server document는 &quot;_id&quot;와 &quot;host&quot;를 가지는데,&lt;br /&gt;
전자는 unique id이고, 후자는 host를 의미한다.&lt;/P&gt;
&lt;P&gt;local.system.replset namespace로 find하여 확인할 수 있다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;replica set의 node&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;어떤 시점에서 하나의 node는 primary고 그 이외는 secondary이다.&lt;br /&gt;
primary node는 필수 master이고, 이후 변경될 수 있다.&lt;/P&gt;
&lt;P&gt;replica set에 공존하는 node의 type은 다음과 같다.&lt;/P&gt;
&lt;P&gt;standard&lt;br /&gt;
; regular replica set node이다. 복사본의 full copy를 보관하고&lt;br /&gt;
새로운 primary를 선출하는데 참여하고 primary로 승격할 자격이 있다.&lt;/P&gt;
&lt;P&gt;passive&lt;br /&gt;
; full copy를 보관하고 선출하는데 참여하지만 primary로 되지 못한다.&lt;/P&gt;
&lt;P&gt;arbiter&lt;br /&gt;
; 단지 선출하는데만 참여한다. 어떤 data도 수신하지 못한다.&lt;br /&gt;
물론 primary로 되지 못한다.&lt;/P&gt;
&lt;P&gt;standard와 passive 차이점은 scale을 더 조개느냐이다.&lt;br /&gt;
arbiter를 제외한 참여 node는 priority 설정이 있다.&lt;br /&gt;
0은 passive를 의미하며 primary로 선출되지 못한다.&lt;br /&gt;
non-zero는 높은 값으로 선출된다. 2개의 1과 1개의 0.5가 있다면,&lt;br /&gt;
3번째는 모든 1이 동작하지 못할때 승격될 수 있다.&lt;/P&gt;
&lt;P&gt;standard와 passive는 다음과 같이 설정된다&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;members&lt;/FONT&gt;&lt;/STRONG&gt;.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;push&lt;/FONT&gt;&lt;/STRONG&gt;({&lt;br /&gt;
&quot;_id&quot;:3,&lt;br /&gt;
&quot;host&quot;:&quot;localhost:10003&quot;,&lt;br /&gt;
&quot;priority&quot;:40&lt;br /&gt;
});&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;members&lt;/FONT&gt;&lt;/STRONG&gt;.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;push&lt;/FONT&gt;&lt;/STRONG&gt;({&lt;br /&gt;
&quot;_id&quot;:4,&lt;br /&gt;
&quot;host&quot;:&quot;localhost:10004&quot;,&lt;br /&gt;
&quot;arbiterOnly&quot;:true&lt;br /&gt;
});&lt;/P&gt;
&lt;P&gt;secondary node는 primary node의 oplog로 부터 pull하고 operation을 적용한다.&lt;br /&gt;
이는 master-slave와 유사하다. secondary node 역시 자신 고유의 local oplog에&lt;br /&gt;
operation을 적용한다. 그러나 primary가 되기 위한 능력을 위해서 이다.&lt;br /&gt;
oplog에 있는 operation은 증가하는 방향으로 단조 증가한다. 이 방향은&lt;br /&gt;
cluster의 임의의 node가 어떻게 최신의 data를 구성하는지 결정하는데 사용된다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;장애극복 및 primary 투표&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;만일 현재의 primary가 down된다면, 나머지 node은 새로운 primary node 선출을 위해 투표를&lt;br /&gt;
시도한다. 이러한 투표 작업은 primary에 도달할 수 없는 임의의 node에 의해 초기화된다.&lt;br /&gt;
새로운 primary는 set의 다수결로 선출된다. arbiter node는 참여하게 되고, 동점 상황일때&lt;br /&gt;
유용하게 사용된다. 새로운 primary는 가장 높은 우선순위를 가지게 된다.&lt;/P&gt;
&lt;P&gt;primary node는 cluster에 있는 다른 node들이 몇개가 살아있는지 추적하기 위해 정보를&lt;br /&gt;
전송한다. 만일 대다수 실패한다면, primary는 자동으로 secondary 상태로 강등된다.&lt;br /&gt;
이는 primary가 network 분리등에 의해 격리됨에도 불구하고 계속 작업을 수행하는것을&lt;br /&gt;
방지한다.&lt;/P&gt;
&lt;P&gt;primary가 변경될때마다 새로운 primary에 있는 data는 system의 가장 최근 data로 간주한다.&lt;br /&gt;
예를들어 이전의 primary node와 같이 다른 node에 의해 적용된 operaiton은 rollback된다.&lt;br /&gt;
물론 이전 primary node가 정상으로 돌아와도 마찬가지 이다.&lt;br /&gt;
이러한 rollback을 수행하기 위해 모든 node는 새로운 primary에 접돌할 때 resync 작업을&lt;br /&gt;
진행한다. 그들은 oplog를 통해 primary에 적용되지 않은 operation을 찾으며&lt;br /&gt;
그러한 operation에 의해 영향받은 document들의 가장 최신 copy를 구하기 위해 새로운 primary를&lt;br /&gt;
query한다. resync중인 node는 recovering이라고 읽으며, 해당 작업이 완료될 때 까지 primary&lt;br /&gt;
투표에 참여하지 않는다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;Slave에 operation 수행하기&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;이러한 master-slave의 가장 중요한 목적은 master node의 down이나 data loss때 장애를 극복하는&lt;br /&gt;
기능을 위해서이다. 또다른 slave의 용도가 있는데, backup을 수행하는데 사용된다.&lt;br /&gt;
또한 scaling out 상태의 read에도 사용된다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;규모로 읽기&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;규모로 읽기 위해서는 slave node를 통해 query하는 것이다. 그로인해 master의 부하는 줄어든다.&lt;br /&gt;
이러한 경우는 보통 다음의 autosharding으로 응용할 수 있다.&lt;/P&gt;
&lt;P&gt;slave로 읽는 것은 쉬운편인데, master-slave 상태에서 query 처리를 위해 slave에 직접 연결하는&lt;br /&gt;
것이다. trick이 있다면, 특수한 query option이 있는데, 어떤 slave server를 쓸 것이냐?도 포함되어 있다.&lt;br /&gt;
(디폴트로 query는 slave에서 수행되지 않는다.)&lt;br /&gt;
이 옵션은 slaveOkay로 불리며, 모든 mongodb driver는 해당 mechanism을 제공하고 있다.&lt;br /&gt;
게다가 몇몇 driver는 자동으로 query를 slave에 분산하여 처리하는 기능도 제공하고 있다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;data processing을 위해 slave 사용하기&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;또다른 재미있는 테크닉은 slave를 극심한 작업이나 집계 작업으로 인한 master 성능 저하가&lt;br /&gt;
발생하는데 이를 떠넘기는 mechanism으로 사용하기도 한다.&lt;br /&gt;
이를 위해서 일반 slave로 시작하되 역시 --master 옵션을 추가하는 것이다.&lt;br /&gt;
즉, --slave와 --master를 같이 쓰는 것이다. 이는 slave에게도 쓰기 권한을 주는 것이며,&lt;br /&gt;
일반적인 mongodb의 master node로도 취급해 준다. 덧붙여 slave에 blocking 작업을 수행할 때,&lt;br /&gt;
master node에 어떠한 성능에 영향을 주지 않도록 한다.&lt;/P&gt;
&lt;P&gt;참고)&lt;br /&gt;
만일 이러한 방법을 사용할 때에는,&lt;br /&gt;
master로 부터 복사된 slave에 어떠한 write도 해서는 안된다.&lt;br /&gt;
slave는 master를 제대로 mirror하기 위해 이러한 write에 대해 되돌리지 않는다.&lt;br /&gt;
slave는 처음으로 시작했을 때 복사된 database를 가져서는 안된다.&lt;br /&gt;
만일 그러했다면, database는 새로운 operation들에대해 update와 sync를 수행하지 않는다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;&lt;FONT color=#ff8b16&gt;* 어떻게 동작하는가?&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;사된 mongodb는 최소한 2개의 server 혹은 node를 구성한다. 하나는 일반 client request를&lt;br /&gt;
처리하는 master이다. 다른 하나는 master에 저장된 data를 mirror하는 책임이 있는 slave이다.&lt;br /&gt;
master는 수행할 모든 operation의 record(기록)를 유지한다. slave는 주기적으로 이러한 새로운&lt;br /&gt;
operation을 master로 부터 polling한다. 그리고 복사된 data로 수행한다. master node의 모든&lt;br /&gt;
동일한 operation을 수행함으로서 slave는 master의 항상 최신 data로 유지할 수 있다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;oplog&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;master가 유지하는 operation record는 oplog(operation log)라 불린다.&lt;br /&gt;
oplog는 local이라는 특별한 database에 저장되며 collection은 oplog.$main이다.&lt;br /&gt;
oplog의 각 document는 master에서 수행할 단일 operation을 표현한 것이다.&lt;br /&gt;
몇개의 key와 다음을 포함하고 있다.&lt;/P&gt;
&lt;P&gt;db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;oplog&lt;/FONT&gt;&lt;/STRONG&gt;.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;$main&lt;/FONT&gt;&lt;/STRONG&gt;.find()&lt;br /&gt;
{ &quot;ts&quot; : { &quot;t&quot; : 1317191495000, &quot;i&quot; : 1 }, &quot;op&quot; : &quot;n&quot;, &quot;ns&quot; : &quot;&quot;, &quot;o&quot; : { } }&lt;br /&gt;
...&lt;br /&gt;
{ &quot;ts&quot; : { &quot;t&quot; : 1317191614000, &quot;i&quot; : 1 }, &quot;op&quot; : &quot;i&quot;, &quot;ns&quot; : &quot;a.b&quot;, &quot;o&quot; : { &quot;_id&quot; : ObjectId(&quot;4e82bfbef2fc774ee41c041d&quot;), &quot;c&quot; : 1 } }&lt;br /&gt;
{ &quot;ts&quot; : { &quot;t&quot; : 1317191619000, &quot;i&quot; : 1 }, &quot;op&quot; : &quot;n&quot;, &quot;ns&quot; : &quot;&quot;, &quot;o&quot; : { } }&lt;br /&gt;
...&lt;/P&gt;
&lt;P&gt;ts&lt;br /&gt;
; timestamp.&lt;/P&gt;
&lt;P&gt;op&lt;br /&gt;
; 1byte의 operation type (&quot;i&quot;는 insert)&lt;/P&gt;
&lt;P&gt;ns&lt;br /&gt;
; operation이 수행할 namespace&lt;/P&gt;
&lt;P&gt;o&lt;br /&gt;
; 수행할 operation을 기술. insert인 경우 insert할 document가 들어감.&lt;/P&gt;
&lt;P&gt;oplog의 중요한 부분은 database의 상태를 변경할 operation만 단지 저장하는 것이다.&lt;br /&gt;
예를 들어 query는 oplog에 저장되지 않는다. 즉, data를 쓰는 논리에만 oplog가&lt;br /&gt;
적용되도록 한다.&lt;/P&gt;
&lt;P&gt;oplog에 저장된 operaton은 master 그 자신이 정확하게 수행했다고는 말할 수 없다.&lt;br /&gt;
이 operation은 저장전 변환되는데, 이는 slave에서 여러번 수행될 operation은&lt;br /&gt;
올바른 순서대로 적용되도록 하는 것이다.&lt;br /&gt;
(예를들어, &quot;$inc&quot;는 &quot;$set&quot;으로 변환된다)&lt;/P&gt;
&lt;P&gt;마지막으로 이는 capped collection에 저장된다. oplog에 저장된 새로운 operation은,&lt;br /&gt;
자동으로 가장 오래된 operation 위치에 저장된다. 이는 oplog가 영원히 커지는것을&lt;br /&gt;
방지한다. 그 크기는 --oplogSize로 전달된다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;sync&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;slave가 처음 시작하면 master node로 부터 full sync를 하게된다.&lt;br /&gt;
slave는 master node로 부터 모든 document를 copy 하는데, 이는 명백히 비용이 드는 작업이다.&lt;br /&gt;
초기 sync가 완료되고 slave는 master의 oplog를 query하고 적용한다.&lt;/P&gt;
&lt;P&gt;slave로 operation을 요청하는 application이 만일 master로 부터 수행해야할 operation이 아직도&lt;br /&gt;
많은 상태인 slave였다면 그 slave는 out of sync가 된다.&lt;/P&gt;
&lt;P&gt;slave가 out-of-sync가 되면 복사는 중지되며 master로 부터 fully resync된다.&lt;br /&gt;
이러한 resync는 {&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;resync&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:1}에 의해 수행되며, --autoresync가 있다면 자동으로 수행된다.&lt;br /&gt;
어떻든, resync는 고비용 operation으로 피해야 한다.&lt;/P&gt;
&lt;P&gt;이와 같이 slave의 sync를 방지하기 위해서, 큰 큰기의 oplog가 필요하다. 큰 oplog는&lt;br /&gt;
disk 크기를 많이 잡으나, 일반적으로 sync하는 비용과 trade-off이다.&lt;br /&gt;
(oplog 크기의 디폴트 값은 5% 이다)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;상태 복사와 local database&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;local database는 내부 복사 상태 용도로 사용되는데, 이는 master와 slave 모두 적용된다.&lt;br /&gt;
local database의 이름은 local이며, 해당 내용은 절대로 복사되지 않는다.&lt;/P&gt;
&lt;P&gt;slave의 list를 포함하는 master에 다른 복사 상태가 저장된다.&lt;br /&gt;
이는 다음과 같이 slave collection에 저장된다.&lt;/P&gt;
&lt;P&gt;db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;slaves&lt;/FONT&gt;&lt;/STRONG&gt;.find()&lt;br /&gt;
{ &quot;_id&quot; : ObjectId(&quot;4e82bf6775761b5c62350281&quot;), &quot;host&quot; : &quot;127.0.0.1&quot;, &quot;ns&quot; : &quot;local.oplog.$main&quot;, &quot;syncedTo&quot; : { &quot;t&quot; : 1317195164000, &quot;i&quot; : 1 } }&lt;/P&gt;
&lt;P&gt;slave는 역시 local database에 상태가 저장된다. 이는 sources collection에 저장된다.&lt;/P&gt;
&lt;P&gt;db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;sources&lt;/FONT&gt;&lt;/STRONG&gt;.find()&lt;br /&gt;
{ &quot;_id&quot; : ObjectId(&quot;4e82bf6775761b5c62350280&quot;), &quot;host&quot; : &quot;localhost:10000&quot;, &quot;source&quot; : &quot;main&quot;, &quot;syncedTo&quot; : { &quot;t&quot; : 1317195224000, &quot;i&quot; : 1 }, &quot;localLogTs&quot; : { &quot;t&quot; : 0, &quot;i&quot; : 0 } }&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;복사를 위한 blocking&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;mongodb의 getLastError 명령시 w parameter를 추가하여, 개발자로 하여금 최신의 복사에 대한 정보를&lt;br /&gt;
구하는것을 보장한다&lt;br /&gt;
getLastError는 최소한 N server가 복사될때까지 block된다.&lt;/P&gt;
&lt;P&gt;db.runCommand({&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;getLastError&lt;/FONT&gt;&lt;/STRONG&gt;:1, &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;w&lt;/FONT&gt;&lt;/STRONG&gt;:N})&lt;/P&gt;
&lt;P&gt;만약 N이 없거나 2보다 작은 경우 즉시 리턴된다.&lt;br /&gt;
만약 N이 2라면 최소한 하나의 slave에서 복사가 이뤄질때까지 block된다.&lt;br /&gt;
master는 local.slaves에 저장된 &quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;syncedTo&lt;/FONT&gt;&lt;/STRONG&gt;&quot; 정보를 이용하여 각 slave를 추적한다.&lt;/P&gt;
&lt;P&gt;w가 지정되면 getLastError는 &quot;wtimeout&quot;을 추가로 받는데, 해당 작업의 timeout을&lt;br /&gt;
millisecond로 지정한 것이다. 디폴트로는 no timeout이다.&lt;/P&gt;
&lt;P&gt;복사를 위한 blocking은 write 작업을 상당히 느리게한다.&lt;br /&gt;
2~3개의 중요한 operation에 적용하여 보다 효과적이고 안전하게 할 수 있다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;* Administration&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;진단&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;mongodb는 복사의 상태를 검증하는데 사용하는 몇가지 유용한 helper를 제공한다.&lt;br /&gt;
master에 연결될 때, 다음과 같은 정보를 볼 수 있다.&lt;/P&gt;
&lt;P&gt;db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;printReplicationInfo&lt;/FONT&gt;&lt;/STRONG&gt;()&lt;br /&gt;
configured oplog size:&amp;nbsp;&amp;nbsp; 944.1375732421875MB&lt;br /&gt;
log length start to end: 5633secs (1.56hrs)&lt;br /&gt;
oplog first event time:&amp;nbsp; Tue Sep 27 2011 23:31:35 GMT-0700 (PDT)&lt;br /&gt;
oplog last event time:&amp;nbsp;&amp;nbsp; Wed Sep 28 2011 01:05:28 GMT-0700 (PDT)&lt;br /&gt;
now:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Wed Sep 28 2011 01:05:32 GMT-0700 (PDT)&lt;br /&gt;
&amp;gt; exit&lt;br /&gt;
bye&lt;br /&gt;
$ &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;mongo&lt;/STRONG&gt; &lt;/FONT&gt;localhost:10001&lt;br /&gt;
MongoDB shell version: 1.8.3&lt;br /&gt;
connecting to: localhost:10001/test&lt;br /&gt;
&amp;gt; db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;printReplicationInfo&lt;/FONT&gt;&lt;/STRONG&gt;()&lt;br /&gt;
{ &quot;errmsg&quot; : &quot;neither master/slave nor replica set replication detected&quot; }&lt;/P&gt;
&lt;P&gt;역시 비슷하게 다음과 같이 slave의 정보를 구할 수 있다.&lt;br /&gt;
db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;printSlaveReplicationInfo&lt;/FONT&gt;&lt;/STRONG&gt;()&lt;br /&gt;
source:&amp;nbsp;&amp;nbsp; localhost:10000&lt;br /&gt;
&amp;nbsp; syncedTo: Wed Sep 28 2011 01:09:18 GMT-0700 (PDT)&lt;br /&gt;
&amp;nbsp;&amp;nbsp; = 17secs ago (0hrs)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;Oplog 크기 변경하기&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;가장 간단한 방법은 master를 stop하고 local database file을 삭제하고 --oplogSize로 재시작하는 것이다.&lt;br /&gt;
이는 다음과 같다.&lt;br /&gt;
$ &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;rm&lt;/STRONG&gt; &lt;/FONT&gt;/data/db/local.*&lt;br /&gt;
$ &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;mongod&lt;/STRONG&gt; &lt;/FONT&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;--master --oplogSize&lt;/STRONG&gt; &lt;/FONT&gt;xxxx&lt;br /&gt;
(xxxx는 MB 크기)&lt;/P&gt;
&lt;P&gt;이 작업 이후에는 모든 slave들도 재시작되어야 하며 &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;--autoresync&lt;/FONT&gt;&lt;/STRONG&gt;를 수행해야 한다.&lt;/P&gt;
&lt;P&gt;미리 oplog 크기를 크게 잡아버리면 master node로 부터 downtime을 증가시키는&lt;br /&gt;
현상을 야기한다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;인증과 함께 복사&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;만일 mongodb 인증과 함께 복사하고자 한다면, configuration을 추가로 해야 한다.&lt;br /&gt;
master slave모두 user는 local database에 추개해야하는데, 동일한 user와 password이여야&lt;br /&gt;
한다. local database의 user는 admin의 user와 비슷한다.&lt;/P&gt;
&lt;P&gt;slave가 master에 접속할 때, local.system.users에 저장된 user로 인증한다.&lt;br /&gt;
시도한 첫 username이 &quot;repl&quot;이고 해당 user가 없다면 local.system.users에 있는 처음것을&lt;br /&gt;
사용한다. 따라서 인증과 함께 복사하려면 master와 slave모두 다음과 같이 실행해야 한다.&lt;/P&gt;
&lt;P&gt;use local&lt;br /&gt;
switched to db local&lt;br /&gt;
db.addUser(&quot;repl&quot;, password);&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &quot;user&quot;:&quot;repl&quot;,&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &quot;readOnly&quot;:false,&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &quot;pwd&quot;:&quot;...&quot;&lt;br /&gt;
}&lt;br /&gt;
그럼 slave는 master로 부터 복사를 수행할 수 있다.&lt;/P&gt;&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-108-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-108-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=20944684&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/108&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/Research&quot;&gt;Research&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/Research/mongodb&quot;&gt;mongodb&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/109&quot; &gt;[mongodb] Sharding&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/10/06&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/108&quot; &gt;[mongodb] Replication&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/107&quot; &gt;[mongodb] Administration&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/106&quot; &gt;[mongodb] Advanced topics&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/105&quot; &gt;[mongodb] Aggregation (MapReduce)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/104&quot; &gt;[mongodb] Indexing&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/22&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>mongodb</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/108</guid>
			<comments>http://greenfishblog.tistory.com/108#entry108comment</comments>
			<pubDate>Wed, 28 Sep 2011 18:22:41 +0900</pubDate>
		</item>
		<item>
			<title>[mongodb] Administration</title>
			<link>http://greenfishblog.tistory.com/107</link>
			<description>&lt;P&gt;mongodb를 관리하는 것은 간단하다.&lt;br /&gt;
backup에서 부터 multinode system 구축까지 다수의 관리 기능은 빠르며 단순하다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;* mongodb 시작/종료하기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;명령줄로 부터 시작하기&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;mongodb는 mongod로 시작한다.&lt;br /&gt;
mongod --help를 통해 확인된다.&lt;br /&gt;
주로 사용되는 옵션을 다음과 같다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;--dbpath&lt;br /&gt;
; data directory를 지정한다. 보통 /data/db가 사용된다.&lt;br /&gt;
mongod process는 고유의 directory가 필요하다.&lt;br /&gt;
시작하면 mongod.lock 파일을 생성하여 다른 mongodb의 접근을 배제한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;--port&lt;br /&gt;
; server에서 listen할 port를 지정한다. 디폴트로 27017이다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;--fork&lt;br /&gt;
; server process를 fork한다. daemon처럼 실행한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;--logpath&lt;br /&gt;
; 로그 파일을 지정한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;--config&lt;br /&gt;
; configuration 파일을 지정한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;./mongod --port 5586 --fork --logpath mongodb.log&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;종료하기&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;SIGINT 혹은 SIGTERM signal을 전송한다.&lt;br /&gt;
만일 mongod의 PID가 1111이라면 &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;kill&lt;/FONT&gt;&lt;/STRONG&gt; &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;-2&lt;/FONT&gt;&lt;/STRONG&gt; 1111(SIGINT) 혹은 &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;kill&lt;/FONT&gt;&lt;/STRONG&gt; 1111(SIGTERM)한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;혹은,&lt;br /&gt;
use admin&lt;br /&gt;
switched to db admin&lt;br /&gt;
db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;shutdownServer&lt;/FONT&gt;&lt;/STRONG&gt;();&lt;br /&gt;
server should be down...&lt;br /&gt;
과 같은 명령으로도 가능하다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;* 모니터하기&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;admin interface 사용&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;기본으로 mongod는 기본적인 http server를 listen한다.&lt;br /&gt;
&lt;A href=&quot;http://localhost:28017/&quot;&gt;http://localhost:28017&lt;/A&gt;을 통해 확인할 수 있다.&lt;br /&gt;
&lt;div class=&quot;imageblock&quot; style=&quot;display:inline;&quot;&gt;&lt;a href=&quot;http://cfile24.uf.tistory.com/original/142F99384E7C45DC0312B6&quot; rel=&quot;lightbox&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://cfile24.uf.tistory.com/image/142F99384E7C45DC0312B6&quot; alt=&quot;&quot; filemime=&quot;&quot; filename=&quot;cfile24.uf@142F99384E7C45DC0312B6.png&quot; height=&quot;232&quot; width=&quot;310&quot;/&gt;&lt;/a&gt;&lt;/div&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;(혹시 관리페이지에서 &lt;br /&gt;
REST is not enabled. use --rest...&lt;br /&gt;
와 같은 오류가 발생하면,&lt;br /&gt;
sudo &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;gedit&lt;/FONT&gt;&lt;/STRONG&gt; /etc/mongod.conf 해서&lt;br /&gt;
&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;rest=true&lt;br /&gt;
&lt;/FONT&gt;&lt;/STRONG&gt;를 추가하고,&lt;br /&gt;
sudo&amp;nbsp;service mongodb restart&lt;br /&gt;
하면 된다.)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;serverStatus&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;가장 기본적인 통계이다.&lt;br /&gt;
&lt;br /&gt;{ &quot;host&quot; : &quot;ubuntu&quot;,&lt;br /&gt;
&amp;nbsp; &quot;version&quot; : &quot;1.8.3&quot;,&lt;br /&gt;
&amp;nbsp; &quot;process&quot; : &quot;mongod&quot;,&lt;br /&gt;
&amp;nbsp; &quot;uptime&quot; : 247,&lt;br /&gt;
&amp;nbsp; &quot;uptimeEstimate&quot; : 202,&lt;br /&gt;
&amp;nbsp; &quot;localTime&quot; : { &quot;$date&quot; : &quot;Fri Sep 23 00:25:10 2011&quot; },&lt;br /&gt;
&amp;nbsp; &quot;globalLock&quot; : { &quot;totalTime&quot; : 247596997,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;lockTime&quot; : 2867759,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;ratio&quot; : 0.01158236583943706,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;currentQueue&quot; : { &quot;total&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;readers&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;writers&quot; : 0 },&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;activeClients&quot; : { &quot;total&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;readers&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;writers&quot; : 0 } },&lt;br /&gt;
&amp;nbsp; &quot;mem&quot; : { &quot;bits&quot; : 64,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;resident&quot; : 13,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;virtual&quot; : 3674,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;supported&quot; : true,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;mapped&quot; : 3600 },&lt;br /&gt;
&amp;nbsp; &quot;connections&quot; : { &quot;current&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;available&quot; : 16000 },&lt;br /&gt;
&amp;nbsp; &quot;extra_info&quot; : { &quot;note&quot; : &quot;fields vary by platform&quot;,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;heap_usage_bytes&quot; : 859376,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;page_faults&quot; : 196 },&lt;br /&gt;
&amp;nbsp; &quot;indexCounters&quot; : { &quot;btree&quot; : { &quot;accesses&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;hits&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;misses&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;resets&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;missRatio&quot; : 0 } },&lt;br /&gt;
&amp;nbsp; &quot;backgroundFlushing&quot; : { &quot;flushes&quot; : 4,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;total_ms&quot; : 1,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;average_ms&quot; : 0.25,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;last_ms&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;last_finished&quot; : { &quot;$date&quot; : &quot;Fri Sep 23 00:25:03 2011&quot; } },&lt;br /&gt;
&amp;nbsp; &quot;cursors&quot; : { &quot;totalOpen&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;clientCursors_size&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;timedOut&quot; : 0 },&lt;br /&gt;
&amp;nbsp; &quot;network&quot; : { &quot;bytesIn&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;bytesOut&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;numRequests&quot; : 0 },&lt;br /&gt;
&amp;nbsp; &quot;opcounters&quot; : { &quot;insert&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;query&quot; : 1,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;update&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;delete&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;getmore&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;command&quot; : 0 },&lt;br /&gt;
&amp;nbsp; &quot;asserts&quot; : { &quot;regular&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;warning&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;msg&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;user&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;rollovers&quot; : 0 },&lt;br /&gt;
&amp;nbsp; &quot;writeBacksQueued&quot; : false }&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;globalLock은 server에서 write lock하는데 걸린 시간을 표기한다. (millisecond)&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;mem은 memory mapped된 가상 메모리 크기이다. (MB)&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;indexCounters는 disk를 읽어야 하는 B-Tree 검색 개수 정보 (miss)와&lt;br /&gt;
memory를 통한 검색 개수 정보(hits)&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;backgroundFlushing은 fsync가 수행되고 걸린 시간이다.&lt;br /&gt;
opcount는 중요한 값으로, 주요 operation의 count를 표시한다.&lt;br /&gt;
asserts는 server에서 발생한 assert의 개수이다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;mongostat&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;serverStatus와 비슷한 정보를 매초 출력한다.&lt;br /&gt;
/usr/bin/mongostat을 통해 실행한다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;* 보안과 인증&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;관리자에게 가장 우선순위가 높은 작업이 보안이다.&lt;br /&gt;
mongodb는 connection별 인증을 지원한다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;인증 기초&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;각각의 database는 user의 개수를 가지고 있다.&lt;br /&gt;
만일 security가 enable이라면, 인증된 user만이 read/write할 수 있다.&lt;br /&gt;
인증에서 mongodb는 db를 admin처럼 다룬다.&lt;br /&gt;
admin database의 user는 superuser로 간주된다. 인증 이후,&lt;br /&gt;
admin user는 어떤 database에서도 read/write 가능하며, listDatabases 혹은 shutdown&lt;br /&gt;
명령도 가능해 진다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;securty가 on되기 전, 최소 하나 이상의 다른 admin user를 추가해야 한다&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;use&lt;/STRONG&gt; &lt;/FONT&gt;admin&lt;br /&gt;
switched to db admin&lt;br /&gt;
db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;addUser&lt;/FONT&gt;&lt;/STRONG&gt;(&quot;root&quot;,&quot;password&quot;)&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&quot;user&quot; : &quot;root&quot;,&lt;br /&gt;
&amp;nbsp;&quot;readOnly&quot; : false,&lt;br /&gt;
&amp;nbsp;&quot;pwd&quot; : &quot;d60e7db4538202339acd585fa951c5aa&quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;use&lt;/FONT&gt;&lt;/STRONG&gt; dbauth&lt;br /&gt;
switched to db dbauth&lt;br /&gt;
db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;addUser&lt;/FONT&gt;&lt;/STRONG&gt;(&quot;test_user&quot;,&quot;1234&quot;);&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&quot;user&quot; : &quot;test_user&quot;,&lt;br /&gt;
&amp;nbsp;&quot;readOnly&quot; : false,&lt;br /&gt;
&amp;nbsp;&quot;pwd&quot; : &quot;5d6323b8d8cb698fb2a1f4a411209d6f&quot;&lt;br /&gt;
}&lt;br /&gt;
db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;addUser&lt;/FONT&gt;&lt;/STRONG&gt;(&quot;test_user_read&quot;,&quot;5678&quot;,&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;true&lt;/FONT&gt;&lt;/STRONG&gt;);&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&quot;user&quot; : &quot;test_user_read&quot;,&lt;br /&gt;
&amp;nbsp;&quot;readOnly&quot; : true,&lt;br /&gt;
&amp;nbsp;&quot;pwd&quot; : &quot;e8c568df8e2e62cfc977e6dba5429e78&quot;&lt;br /&gt;
}&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;이제 sudo &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;gedit&lt;/STRONG&gt; &lt;/FONT&gt;/etc/mongodb.conf에서&lt;br /&gt;
#auth = true&lt;br /&gt;
를&lt;br /&gt;
&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;auth = true&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
로 변경하고 sudo service mongodb restart하자.&lt;br /&gt;
혹은 mongod --auth해도 된다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;그럼 다음과 같다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;use&lt;/STRONG&gt; &lt;/FONT&gt;dbauth&lt;br /&gt;
switched to db dbauth&lt;br /&gt;
db.a.find()&lt;br /&gt;
error: {&lt;br /&gt;
&amp;nbsp;&quot;$err&quot; : &quot;unauthorized db:dbauth lock type:-1 client:127.0.0.1&quot;,&lt;br /&gt;
&amp;nbsp;&quot;code&quot; : 10057&lt;br /&gt;
}&lt;br /&gt;
db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;auth&lt;/FONT&gt;&lt;/STRONG&gt;(&quot;test_user_read&quot;, &quot;5677&quot;)&lt;br /&gt;
0&lt;br /&gt;
db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;auth&lt;/FONT&gt;&lt;/STRONG&gt;(&quot;test_user_read&quot;, &quot;5678&quot;)&lt;br /&gt;
1&lt;br /&gt;
db.a.find()&lt;br /&gt;
db.a.insert({&quot;a&quot;:1})&lt;br /&gt;
unauthorized&lt;br /&gt;
db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;auth&lt;/FONT&gt;&lt;/STRONG&gt;(&quot;test_user&quot;, &quot;1234&quot;)&lt;br /&gt;
1&lt;br /&gt;
db.a.insert({&quot;a&quot;:1})&lt;br /&gt;
db.a.find()&lt;br /&gt;
{ &quot;_id&quot; : ObjectId(&quot;4e7c3b02b663ec8d86596a43&quot;), &quot;a&quot; : 1 }&lt;br /&gt;
show &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;dbs&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
Fri Sep 23 00:54:07 uncaught exception: listDatabases failed:{&lt;br /&gt;
&amp;nbsp;&quot;assertion&quot; : &quot;unauthorized db:admin lock type:-1 client:127.0.0.1&quot;,&lt;br /&gt;
&amp;nbsp;&quot;assertionCode&quot; : 10057,&lt;br /&gt;
&amp;nbsp;&quot;errmsg&quot; : &quot;db assertion failure&quot;,&lt;br /&gt;
&amp;nbsp;&quot;ok&quot; : 0&lt;br /&gt;
}&lt;br /&gt;
use &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;admin&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
switched to db admin&lt;br /&gt;
&amp;gt; db.a.find()&lt;br /&gt;
error: {&lt;br /&gt;
&amp;nbsp;&quot;$err&quot; : &quot;unauthorized db:admin lock type:-1 client:127.0.0.1&quot;,&lt;br /&gt;
&amp;nbsp;&quot;code&quot; : 10057&lt;br /&gt;
}&lt;br /&gt;
&amp;gt; db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;auth&lt;/FONT&gt;&lt;/STRONG&gt;(&quot;root&quot;,&quot;password&quot;)&lt;br /&gt;
1&lt;br /&gt;
&amp;gt; show &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;dbs&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
...&lt;/P&gt;
&lt;P&gt;&lt;br /&gt;
&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;인증 방법&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;주어진 database의 user 정보는 system.users collection에 저장된다.&lt;br /&gt;
{&quot;user&quot;:username, &quot;readOnly&quot;:true, &quot;pwd&quot;:password hash}와 같은 구조이다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;다음은 user를 삭제하는 과정이다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.auth(&quot;test_user&quot;,&quot;1234&quot;);&lt;br /&gt;
0&lt;br /&gt;
use dbauth&lt;br /&gt;
switched to db dbauth&lt;br /&gt;
db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;auth&lt;/FONT&gt;&lt;/STRONG&gt;(&quot;test_user&quot;,&quot;1234&quot;);&lt;br /&gt;
1&lt;br /&gt;
db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;system.users.remove&lt;/FONT&gt;&lt;/STRONG&gt;({&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;user&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:&quot;test_user&quot;});&lt;br /&gt;
db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;auth&lt;/FONT&gt;&lt;/STRONG&gt;(&quot;test_user&quot;,&quot;1234&quot;);&lt;br /&gt;
0&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;다른 보안 고려사항&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;인증시 mongodb protocol은 encrypt되지 않는다. 만약 필요하다면, SSH tuenneling 혹은&lt;br /&gt;
다른 encrypt 방식을 사용해야 한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;보통 mongodb server는 firewall 혹은 network access 뒷편에 있어야 하는것을 추천한다.&lt;br /&gt;
만일 mongodb server가 other world와 access된다면 --bindip를 사용할 것을 추천한다.&lt;br /&gt;
그것은 bound될 local ip 주소를 지정하도록 만들어주기 때문이다.&lt;br /&gt;
예를 들어, 동일 machine에서만 접근 가능토록 하려면 mongod --bindip localhost와 같이 한다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;&lt;FONT color=#ff8b16&gt;* Backup과 Repair&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;Data file backup&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;mongodb는 모든 data를 data directory에 저장한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;mongodb가 실행중일때 data directory를 copy하는 것은 안전하지 않다.&lt;br /&gt;
mongodb를 shutdown한 뒤 작업한다.&lt;br /&gt;
비록 shutdown과 copy는 효과적이고 안전하지만, 이상적이진 않다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;mongodump와 mongorestore&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;mongodump&lt;/STRONG&gt; &lt;/FONT&gt;utility를 통해 모든 mongodb 분산 시스템까지 backup할 수 있다.&lt;br /&gt;
mongodump는 실행중인 mongodb server에 대해 query 작업을 한다. 그리고&lt;br /&gt;
모든 document들을 disk에 저장한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;/usr/bin$ &lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;mongodump&lt;/STRONG&gt; &lt;/FONT&gt;--help&lt;br /&gt;
options:&lt;br /&gt;
&amp;nbsp; --help&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; produce help message&lt;br /&gt;
&amp;nbsp; -v [ --verbose ]&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; be more verbose (include multiple times for more &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; verbosity e.g. -vvvvv)&lt;br /&gt;
&amp;nbsp; -h [ --host ] arg&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mongo host to connect to ( &amp;lt;set name&amp;gt;/s1,s2 for &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sets)&lt;br /&gt;
&amp;nbsp; --port arg&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; server port. Can also use --host hostname:port&lt;br /&gt;
&amp;nbsp; --ipv6&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; enable IPv6 support (disabled by default)&lt;br /&gt;
&amp;nbsp; -u [ --username ] arg&amp;nbsp;&amp;nbsp;&amp;nbsp; username&lt;br /&gt;
&amp;nbsp; -p [ --password ] arg&amp;nbsp;&amp;nbsp;&amp;nbsp; password&lt;br /&gt;
&amp;nbsp; --dbpath arg&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; directly access mongod database files in the given &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; path, instead of connecting to a mongod&amp;nbsp; server - &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; needs to lock the data directory, so cannot be used &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if a mongod is currently accessing the same path&lt;br /&gt;
&amp;nbsp; --directoryperdb&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if dbpath specified, each db is in a separate &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; directory&lt;br /&gt;
&amp;nbsp; -d [ --db ] arg&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; database to use&lt;br /&gt;
&amp;nbsp; -c [ --collection ] arg&amp;nbsp; collection to use (some commands)&lt;br /&gt;
&amp;nbsp; -o [ --out ] arg (=dump) output directory or &quot;-&quot; for stdout&lt;br /&gt;
&amp;nbsp; -q [ --query ] arg&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; json query&lt;br /&gt;
&amp;nbsp; --oplog&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Use oplog for point-in-time snapshotting&lt;br /&gt;
&amp;nbsp; --repair&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; try to recover a crashed database&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;~$ /usr/bin/&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;mongodump&lt;/STRONG&gt; &lt;/FONT&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;-d&lt;/FONT&gt;&lt;/STRONG&gt; test &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;-o&lt;/FONT&gt;&lt;/STRONG&gt; backup&lt;br /&gt;
connected to: 127.0.0.1&lt;br /&gt;
DATABASE: test&amp;nbsp; to &amp;nbsp;backup/test&lt;br /&gt;
&amp;nbsp;test.system.indexes to backup/test/system.indexes.bson&lt;br /&gt;
&amp;nbsp;&amp;nbsp; 4 objects&lt;br /&gt;
&amp;nbsp;test.fs.files to backup/test/fs.files.bson&lt;br /&gt;
&amp;nbsp;&amp;nbsp; 1 objects&lt;br /&gt;
&amp;nbsp;test.fs.chunks to backup/test/fs.chunks.bson&lt;br /&gt;
&amp;nbsp;&amp;nbsp; 1 objects&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;와 같이 백업할 수 있다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;그리고 이와 유사하게 &lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;mongorestore&lt;/FONT&gt;&lt;/STRONG&gt;를 사용한다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;fsync와 lock&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;mongodump와 mongorestore는 shutdown없이 backup할 수 있도록 한다.&lt;br /&gt;
이는 저장할 싯점의 변경사항은 lose할 수 있다.&lt;br /&gt;
fsync는 동작중일때, data directory를 복사하는 것으로, 다른 충돌 위험이 없다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;fsync&lt;/FONT&gt;&lt;/STRONG&gt;는 server에게 flush를 강제로 명령하여, 대기된 disk 쓰기 작업을 진행시킨다.&lt;br /&gt;
그리고, server가 lock이 풀릴때까지 database를 쓰는 것을 방지하도록 lock한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;use admin&lt;br /&gt;
switched to db admin&lt;br /&gt;
db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;runCommand&lt;/FONT&gt;&lt;/STRONG&gt;({&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;fsync&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:1, &quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;lock&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:1});&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&quot;info&quot; : &quot;now locked against writes, use db.$cmd.sys.unlock.findOne() to unlock&quot;,&lt;br /&gt;
&amp;nbsp;&quot;ok&quot; : 1&lt;br /&gt;
}&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;이 싯점에서, data directory는 일관성이 있다. 왜냐하면 lock되었기 때문이다.&lt;br /&gt;
이때 우리는 안전하게 data directory를 복사할 수 있다.&lt;br /&gt;
복사가 종료되었다면, 다음과 같이 unlock한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;$cmd.sys.unlock.findOne&lt;/FONT&gt;&lt;/STRONG&gt;();&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
{ &quot;ok&quot; : 1, &quot;info&quot; : &quot;unlock requested&quot; }&lt;br /&gt;
db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;currentOp&lt;/FONT&gt;&lt;/STRONG&gt;();&lt;br /&gt;
{ &quot;inprog&quot; : [ ] }&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;slave backup&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;slave server 백업은 위 방법으로 적용된다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;repair&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;재앙이 발생했다면, backup을 찾게된다.&lt;br /&gt;
그러나 불행이도 backup이 없는 경우도 있을 것이다.&lt;br /&gt;
여하튼, mongodb는 built-in repairing 기능이 있다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;repair는 unclean shutdown뒤에 실행해야 한다.&lt;br /&gt;
만일, 그러하다면, 다시 시작시에 아래와 같은 메시지를 받는다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;**************&lt;br /&gt;
old lock file: /data/db/mongod.lock. probably means unclean shutdown&lt;br /&gt;
recommend removing file and running --repair&lt;br /&gt;
see: &lt;A href=&quot;http://dochub.mongodb.org/core/repair&quot;&gt;http://dochub.mongodb.org/core/repair&lt;/A&gt; for more information&lt;br /&gt;
*************&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;이런 경우에 ---repair:mongod --repair를 사용한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;단일 database를 repair하기 위해서는,&lt;br /&gt;
repairDatabase를 호출한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;use test&lt;br /&gt;
switched to db test&lt;br /&gt;
db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;repairDatabase&lt;/FONT&gt;&lt;/STRONG&gt;()&lt;br /&gt;
{ &quot;ok&quot; : 1 }&lt;/P&gt;&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-107-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-107-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=20789313&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/107&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/Research&quot;&gt;Research&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/Research/mongodb&quot;&gt;mongodb&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/109&quot; &gt;[mongodb] Sharding&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/10/06&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/108&quot; &gt;[mongodb] Replication&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/107&quot; &gt;[mongodb] Administration&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/106&quot; &gt;[mongodb] Advanced topics&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/105&quot; &gt;[mongodb] Aggregation (MapReduce)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/104&quot; &gt;[mongodb] Indexing&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/22&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>mongodb</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/107</guid>
			<comments>http://greenfishblog.tistory.com/107#entry107comment</comments>
			<pubDate>Fri, 23 Sep 2011 17:48:54 +0900</pubDate>
		</item>
		<item>
			<title>[mongodb] Advanced topics</title>
			<link>http://greenfishblog.tistory.com/106</link>
			<description>&lt;P&gt;mongodb는 다음과 같은 추가 기능을 제공한다.&lt;/P&gt;
&lt;P&gt;- database command 사용하기&lt;br /&gt;
- 특별 collection인 capped collections와 함께 작업하기&lt;br /&gt;
- 큰 파일 저장을 위한 gridfs 지원&lt;br /&gt;
- server-side JavaScript 지원&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;* database command&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;Commands 작동 원리&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;drop은 shell에서 db.test.drop()와 같이 실행하면 된다.&lt;br /&gt;
이는 db.runCommand({&quot;drop&quot;:&quot;test&quot;});와 같다.&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;Command reference&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;listCommands&lt;/FONT&gt;&lt;/STRONG&gt;()를통해 확인 가능&lt;br /&gt;
&lt;A href=&quot;http://localhost:28017/_commands&quot;&gt;http://localhost:28017/_commands&lt;/A&gt;를 통해 확인 가능&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.runCommand({&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;buildInfo&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:1})&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&quot;version&quot; : &quot;1.8.3&quot;,&lt;br /&gt;
&amp;nbsp;&quot;gitVersion&quot; : &quot;c206d77e94bc3b65c76681df5a6b605f68a2de05&quot;,&lt;br /&gt;
&amp;nbsp;&quot;sysInfo&quot; : &quot;Linux bs-linux64.10gen.cc 2.6.21.7-2.ec2.v1.2.fc8xen #1 SMP Fri Nov 20 17:48:28 EST 2009 x86_64 BOOST_LIB_VERSION=1_41&quot;,&lt;br /&gt;
&amp;nbsp;&quot;bits&quot; : 64,&lt;br /&gt;
&amp;nbsp;&quot;debug&quot; : false,&lt;br /&gt;
&amp;nbsp;&quot;maxBsonObjectSize&quot; : 16777216,&lt;br /&gt;
&amp;nbsp;&quot;ok&quot; : 1&lt;br /&gt;
}&lt;br /&gt;
admin-only command로, mongodb server의 버전을 알려줌.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.runCommand({&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;collStats&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:&quot;a&quot;})&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&quot;ns&quot; : &quot;sss.a&quot;,&lt;br /&gt;
&amp;nbsp;&quot;count&quot; : 3,&lt;br /&gt;
&amp;nbsp;&quot;size&quot; : 108,&lt;br /&gt;
&amp;nbsp;&quot;avgObjSize&quot; : 36,&lt;br /&gt;
&amp;nbsp;&quot;storageSize&quot; : 2048,&lt;br /&gt;
&amp;nbsp;&quot;numExtents&quot; : 1,&lt;br /&gt;
&amp;nbsp;&quot;nindexes&quot; : 1,&lt;br /&gt;
&amp;nbsp;&quot;lastExtentSize&quot; : 2048,&lt;br /&gt;
&amp;nbsp;&quot;paddingFactor&quot; : 1,&lt;br /&gt;
&amp;nbsp;&quot;flags&quot; : 1,&lt;br /&gt;
&amp;nbsp;&quot;totalIndexSize&quot; : 8192,&lt;br /&gt;
&amp;nbsp;&quot;indexSizes&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;_id_&quot; : 8192&lt;br /&gt;
&amp;nbsp;},&lt;br /&gt;
&amp;nbsp;&quot;ok&quot; : 1&lt;br /&gt;
}&lt;br /&gt;
주어진 collection의 data 크기, 할당 크기, index 개수 등을 알려준다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.runCommand({&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;distinct&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:&quot;a&quot;, &quot;key&quot;:&quot;a&quot;, &quot;query&quot;:{}})&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&quot;values&quot; : [&lt;br /&gt;
&amp;nbsp;&amp;nbsp;1,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;2,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;3&lt;br /&gt;
&amp;nbsp;],&lt;br /&gt;
&amp;nbsp;&quot;stats&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;n&quot; : 3,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;nscanned&quot; : 3,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;nscannedObjects&quot; : 3,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;timems&quot; : 0&lt;br /&gt;
&amp;nbsp;},&lt;br /&gt;
&amp;nbsp;&quot;ok&quot; : 1&lt;br /&gt;
}&lt;br /&gt;
주어진 key와 query로 해당 collection의 분산값들을 알려준다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.runCommand({&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;drop&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:&quot;a&quot;})&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&quot;nIndexesWas&quot; : 1,&lt;br /&gt;
&amp;nbsp;&quot;msg&quot; : &quot;indexes dropped for collection&quot;,&lt;br /&gt;
&amp;nbsp;&quot;ns&quot; : &quot;sss.a&quot;,&lt;br /&gt;
&amp;nbsp;&quot;ok&quot; : 1&lt;br /&gt;
}&lt;br /&gt;
주어진 collection을 삭제한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.runCommand({&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;dropDatabase&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:1})&lt;br /&gt;
{ &quot;dropped&quot; : &quot;sss&quot;, &quot;ok&quot; : 1 }&lt;br /&gt;
현재 database를 삭제한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.runCommand({&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;dropIndexes&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:&quot;a&quot;, &quot;index&quot;:&quot;*&quot;})&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&quot;nIndexesWas&quot; : 2,&lt;br /&gt;
&amp;nbsp;&quot;msg&quot; : &quot;non-_id indexes dropped for collection&quot;,&lt;br /&gt;
&amp;nbsp;&quot;ok&quot; : 1&lt;br /&gt;
}&lt;br /&gt;
주어진 index를 삭제한다. *는 모든 index이다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.runCommand({&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;getLastError&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:1})&lt;br /&gt;
현재 connection에서 마지막 수행한 operation의 error 혹은 상태 정보를 알려준다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.runCommand({&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;isMaster&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:1})&lt;br /&gt;
{ &quot;ismaster&quot; : true, &quot;maxBsonObjectSize&quot; : 16777216, &quot;ok&quot; : 1 }&lt;br /&gt;
현재 서버가 master인지 slave인지 알려준다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.runCommand({&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;ping&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:1})&lt;br /&gt;
{ &quot;ok&quot; : 1 }&lt;br /&gt;
서버가 살아 있는지 확인한다. 서버가 lock 상태일 때에도 즉각 리턴된다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.runCommand({&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;renameCollection&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:&quot;sss.a&quot;, &quot;to&quot;:&quot;sss.z&quot;})&amp;nbsp; &lt;br /&gt;
{ &quot;ok&quot; : 1 }&lt;br /&gt;
collection 이름을 변경한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.runCommand({&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;repairDatabase&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:1})&lt;br /&gt;
{ &quot;ok&quot; : 1 }&lt;br /&gt;
현재 database를 repair, compact 한다.&lt;br /&gt;
오래 걸린다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.runCommand({&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;serverStatus&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:1})&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&quot;host&quot; : &quot;ubuntu&quot;,&lt;br /&gt;
&amp;nbsp;&quot;version&quot; : &quot;1.8.3&quot;,&lt;br /&gt;
&amp;nbsp;&quot;process&quot; : &quot;mongod&quot;,&lt;br /&gt;
&amp;nbsp;&quot;uptime&quot; : 1459578,&lt;br /&gt;
&amp;nbsp;&quot;uptimeEstimate&quot; : 88153,&lt;br /&gt;
&amp;nbsp;&quot;localTime&quot; : ISODate(&quot;2011-09-23T01:31:12.355Z&quot;),&lt;br /&gt;
&amp;nbsp;&quot;globalLock&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;totalTime&quot; : 1459577533573,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;lockTime&quot; : 6870046,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;ratio&quot; : 0.000004706872942324854,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;currentQueue&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;total&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;readers&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;writers&quot; : 0&lt;br /&gt;
&amp;nbsp;&amp;nbsp;},&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;activeClients&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;total&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;readers&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;writers&quot; : 0&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;},&lt;br /&gt;
&amp;nbsp;&quot;mem&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;bits&quot; : 64,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;resident&quot; : 8,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;virtual&quot; : 3347,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;supported&quot; : true,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;mapped&quot; : 3200&lt;br /&gt;
&amp;nbsp;},&lt;br /&gt;
&amp;nbsp;&quot;connections&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;current&quot; : 10,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;available&quot; : 15990&lt;br /&gt;
&amp;nbsp;},&lt;br /&gt;
&amp;nbsp;&quot;extra_info&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;note&quot; : &quot;fields vary by platform&quot;,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;heap_usage_bytes&quot; : 2962544,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;page_faults&quot; : 643&lt;br /&gt;
&amp;nbsp;},&lt;br /&gt;
&amp;nbsp;&quot;indexCounters&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;btree&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;accesses&quot; : 6,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;hits&quot; : 6,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;misses&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;resets&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;missRatio&quot; : 0&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;},&lt;br /&gt;
&amp;nbsp;&quot;backgroundFlushing&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;flushes&quot; : 2304,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;total_ms&quot; : 2332,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;average_ms&quot; : 1.0121527777777777,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;last_ms&quot; : 1,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;last_finished&quot; : ISODate(&quot;2011-09-23T01:30:54.191Z&quot;)&lt;br /&gt;
&amp;nbsp;},&lt;br /&gt;
&amp;nbsp;&quot;cursors&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;totalOpen&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;clientCursors_size&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;timedOut&quot; : 0&lt;br /&gt;
&amp;nbsp;},&lt;br /&gt;
&amp;nbsp;&quot;network&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;bytesIn&quot; : 232543,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;bytesOut&quot; : 312930,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;numRequests&quot; : 2993&lt;br /&gt;
&amp;nbsp;},&lt;br /&gt;
&amp;nbsp;&quot;opcounters&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;insert&quot; : 574,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;query&quot; : 328,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;update&quot; : 51,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;delete&quot; : 6,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;getmore&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;command&quot; : 2056&lt;br /&gt;
&amp;nbsp;},&lt;br /&gt;
&amp;nbsp;&quot;asserts&quot; : {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;regular&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;warning&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;msg&quot; : 0,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;user&quot; : 34,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&quot;rollovers&quot; : 0&lt;br /&gt;
&amp;nbsp;},&lt;br /&gt;
&amp;nbsp;&quot;writeBacksQueued&quot; : false,&lt;br /&gt;
&amp;nbsp;&quot;ok&quot; : 1&lt;br /&gt;
}&lt;br /&gt;
서버의 상태를 알린다.&lt;/P&gt;
&lt;P&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;* capped collections&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;mongodb는 동적으로 생성되고, 추가 data를 맞추기 위해 size가 자동으로 커진다.&lt;br /&gt;
mongodb는 capped collection이라는 다른 종류의 collection을 제공한다.&lt;br /&gt;
이는 미리 생성되고 고정 크기를 가진다.&lt;br /&gt;
그럼 Full되면 어떻게 되는가? capped collection은 circular queue이다.&lt;br /&gt;
그래서 oldest가 삭제된다. 즉, capped collection은 자동으로 age-out되는&lt;br /&gt;
구조이다.&lt;/P&gt;
&lt;P&gt;capped collection에서 몇몇 operation은 실행되지 않는다.&lt;br /&gt;
document는 이동/삭제가 되지 않는다.(물론 age-out은 된다)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;특징과 사용예&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;1) 극단적으로 빠르다.&lt;br /&gt;
2) insert 순서대로 document를 구하는 것이 정말 빠르다.&lt;br /&gt;
3) 자동으로 aging-out되는 구조에 적합하다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;주로 log에 사용될 수 있다. 그리고 작은수의 document를 caching하는데 적합하다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;Capped collection 생성예&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;createCollection&lt;/STRONG&gt;&lt;/FONT&gt;(&quot;capped_c&quot;, {&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;capped&lt;/FONT&gt;&lt;/STRONG&gt;:true, size:100000})&lt;br /&gt;
{ &quot;ok&quot; : 1 }&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;100000byte 크기의 capped collection을 생성하였다.&lt;br /&gt;
max:100을 추가하면, collection size도 제한할 수 있다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;이미 있는 일반 collection을 변환하는 것은 다음과 같다.&lt;br /&gt;
db.runCommand({&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;convertToCapped&lt;/FONT&gt;&lt;/STRONG&gt;:&quot;a&quot;, size:10000})&lt;br /&gt;
{ &quot;ok&quot; : 1 }&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;Au Naturel sort&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;capped collection은 natural sort라는 sort를 제공한다.&lt;br /&gt;
natural order는 disk상 보여지는 순서를 의미한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;capped collection은 insert순으로 저장되기 때문에, natural order는 insert order이다.&lt;br /&gt;
역순으로 sort하는 것은 다음과 같다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.a.find().sort({&quot;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;$natural&lt;/FONT&gt;&lt;/STRONG&gt;&quot;:-1})&lt;br /&gt;
{ &quot;_id&quot; : ObjectId(&quot;4e7be67ea832633d57ff5465&quot;), &quot;a&quot; : 3 }&lt;br /&gt;
{ &quot;_id&quot; : ObjectId(&quot;4e7be67ba832633d57ff5464&quot;), &quot;a&quot; : 2 }&lt;br /&gt;
{ &quot;_id&quot; : ObjectId(&quot;4e7be5d9a832633d57ff5463&quot;), &quot;a&quot; : 1 }&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;tailable cursors&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;tailable cursor는 result가 소진되었을때 close되지 않는 영구 cursor를 의미한다.&lt;br /&gt;
이는 tail -f 명령에서 영감받았다. 물론 capped collection에서만 지원된다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;* GridFS : 파일 저장소&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;br /&gt;
&lt;br /&gt;GridFS는 mongodb의 binary file 저장 mechanism을 따른다.&lt;br /&gt;
GridFS를 file 저장소로 사용하는데 다음의 몇가지 이유가 있다.&lt;/P&gt;
&lt;P&gt;- stack을 단순화한다. 다른 file 저장소 architecture를 배제시킨다.&lt;br /&gt;
- autosharding을 지원한다. scale-out이 쉽다.&lt;br /&gt;
- user upload에 따른 filesystem 이슈를 완화한다. 예를 들어, 동일 directory의 파일 개수 제한이 없다.&lt;br /&gt;
- 2GB chunk로 data를 할당하므로, 좋은 disk locality(집약성)을 가진다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;GridFS 시작하기&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;mongofiles utilty를 사용하여 쉽게 GridFS를 실행할 수 있다.&lt;br /&gt;
이는 upload, download를 지원한다.&lt;br /&gt;
mongofiles --help를 통해 명령을 구할 수 있다.&lt;br /&gt;
다음과 같이 file을 upload/download할 수 있다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;~$ echo &quot;Hello, world&quot; &amp;gt; foo.txt&lt;br /&gt;
~$ cd /usr/bin&lt;br /&gt;
/usr/bin$ mongofiles put ~/foo.txt&lt;br /&gt;
connected to: 127.0.0.1&lt;br /&gt;
added file: { _id: ObjectId('4e7bea0cd9d16165bf521e6a'), filename: &quot;/home/greenfish/foo.txt&quot;, chunkSize: 262144, uploadDate: new Date(1316743692450), md5: &quot;a7966bf58e23583c9a5a4059383ff850&quot;, length: 13 }&lt;br /&gt;
done!&lt;br /&gt;
/usr/bin$ mongofiles list&lt;br /&gt;
connected to: 127.0.0.1&lt;br /&gt;
/home/greenfish/foo.txt&amp;nbsp;13&lt;br /&gt;
/usr/bin$ rm ~/foo.txt&lt;br /&gt;
/usr/bin$ mongofiles get /home/greenfish/foo.txt&lt;br /&gt;
connected to: 127.0.0.1&lt;br /&gt;
done write to: /home/greenfish/foo.txt&lt;br /&gt;
/usr/bin$ cat ~/foo.txt&lt;br /&gt;
Hello, world&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;mongodb driver로부터 GridFS 실행하기&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;pyMongo는 다음과 같다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;&amp;gt;&amp;gt;&amp;gt; from pymongo import Connection&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; import gridfs&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; db = Connection().test&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; fs = gridfs.GridFS(db)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; file_id = fs.put(&quot;Hello, world&quot;, filename=&quot;foo.txt&quot;)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; fs.list()&lt;br /&gt;
[u'foo.txt']&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; fs.get(file_id).read()&lt;br /&gt;
'Hello, world'&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;뚜껑을 열고...&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;GridFS의 기본 idea는 큰 file을 chunk로 쪼개고 그것을 document로 하는 것이다.&lt;br /&gt;
mongodb는 binary data를 저장하는 기능을 지원하기 때문에, chunk를 저장하는데&lt;br /&gt;
overhead가 크지 않다.&lt;br /&gt;
각각의 chunk file을 저장하는데 함께 묶어서 저장하며, file의 meta 정보도 포함시킨다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;GrindFS를 위한 chunk는 그들 고유의 collection에 저장된다.&lt;br /&gt;
디폴트로 chunk는 fs.chunks를 사용하며 필요시 무시된다.&lt;br /&gt;
chunk collection내에서 개별 document는 다음과 같이 단순하다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;{&lt;br /&gt;
&amp;nbsp;&quot;_id&quot;:ObjectId(&quot;...&quot;),&lt;br /&gt;
&amp;nbsp;&quot;n&quot;:0,&lt;br /&gt;
&amp;nbsp;&quot;data&quot;:BinData(&quot;...&quot;),&lt;br /&gt;
&amp;nbsp;&quot;files_id&quot;:ObjectId(&quot;...&quot;)&lt;br /&gt;
}&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;file_id는 이 chunk의 metadata를 포함하고 있는 문서의 id이다.&lt;br /&gt;
n은 chunk number이다. original file에 표현된 chunk 순서를 따른다.&lt;br /&gt;
&quot;data&quot;는 chunk를 나타낸 binary data이다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;각 file을 위한 metadata는 다른 collection에 저장되는데, 디폴트로 fs.files이다.&lt;br /&gt;
각 document는 단일 file을 의미한다.&lt;br /&gt;
사용자 정의 key를 추가할 수 있다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;_id&lt;br /&gt;
&amp;nbsp;file의 id. chunk에서 files_id로 사용&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;length&lt;br /&gt;
&amp;nbsp;크기&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;chunkSize&lt;br /&gt;
&amp;nbsp;개별 chunk 크기. 디폴트로 256K&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;uploadData&lt;br /&gt;
&amp;nbsp;저장된 싯점&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;md5&lt;br /&gt;
&amp;nbsp;md5 checksum&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.fs.files.distinct(&quot;filename&quot;)&lt;br /&gt;
[ &quot;foo.txt&quot; ]&lt;br /&gt;
와 같은 결과를 얻는다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;&lt;FONT color=#ff8b16&gt;* Server-side scripting&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;JavaScript는 db.eval function으로 서버에서 실행된다.&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;db.eval&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;주로 multidocument transaction을 모방하는데 사용됟나.&lt;br /&gt;
db.eval은 db lock을 건 다음 JavaScript를 실행하고 db lock을 푼다.&lt;br /&gt;
rollback은 없으나 특정 순서로 operation 작업들 실행하는것을 보장한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;다음과 같이 code를 전송하여 실행할 수 있다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;eval&lt;/FONT&gt;&lt;/STRONG&gt;(&quot;return 1;&quot;) &lt;br /&gt;
1&lt;br /&gt;
db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;eval&lt;/FONT&gt;&lt;/STRONG&gt;(&quot;function() {return 1;}&quot;)&lt;br /&gt;
1&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;저장된 JavaScript&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;system.js라는 특별한 collection이 있는데, JavaScript 변수가 저장된다.&lt;br /&gt;
이 값들은 JavaScript context에서 사용되는 변수로, &quot;$where&quot;나 db.eval 그리고&lt;br /&gt;
MapReduce등이 포함된다.&lt;br /&gt;
system.js에 다음과 같이 변수를 추가할 수 있다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;system.js&lt;/STRONG&gt;&lt;/FONT&gt;.insert({&quot;_id&quot;:&quot;x&quot;, &quot;value&quot;:1})&lt;br /&gt;
db.&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;system.js&lt;/STRONG&gt;&lt;/FONT&gt;.insert({&quot;_id&quot;:&quot;y&quot;, &quot;value&quot;:2})&lt;br /&gt;
db.&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;system.js&lt;/FONT&gt;&lt;/STRONG&gt;.insert({&quot;_id&quot;:&quot;z&quot;, &quot;value&quot;:3})&lt;br /&gt;
db.eval(&quot;return x+y+z;&quot;)&lt;br /&gt;
6&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;system.js는 간단한 JavaScript function도 저장할 수 있다.&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff8b16&gt;&lt;STRONG&gt;보안&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;JavaScript를 실행하는 것은 보안에 신경써야 한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;올바르지 않게 완료되었다면, server-side JavaScript는 injection 공격에&lt;br /&gt;
취약해진다. 운좋게도, 이러한 공격은 쉽게 예방할 수 있다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;&quot;Hello, &amp;lt;username&amp;gt;!&quot; 프로그래이 있을때, 만약 username이 username이라는 변수라면,&lt;br /&gt;
다음과 같이 사용할 수 있다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;func = &quot;function() {print('Hello, &quot;+username+&quot;!');}&quot;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;혹은 만약 username이 user-=defined 변수라면, &quot;문자를 포함할 수 있다.&lt;br /&gt;
즉, &quot;'); db.dropDatabase(); print('&quot;와 같을 수 있다. 이런 경우 다음과 같은 효과가 있다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;func = &quot;function() { print('Hello, '); db.dropDatabase(); print('!'); }&quot;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;그러면, 전체 db가 삭제될 것이다!&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;이를 방지하려면, username을 전달할 때 scope를 사용해야 한다.&lt;br /&gt;
예를 들어, PHP에서,&lt;br /&gt;
$func = new MongoCode(&quot;function() {print('Hello, &quot;+username+&quot;!');}&quot;, array(&quot;username&quot; =&amp;gt; $username));&lt;br /&gt;
와 같을 것이다.&lt;br /&gt;
그러면, database는 유해하지 않게 이와 같이 출력한다.&lt;br /&gt;
Hello, '); db.dropDatabase(); print('!&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;대부분의 driver는 database에 code를 전송할 때 특정 type이 있는데,&lt;br /&gt;
code는 string과 scope가 결합되어 있을 수 있다.&lt;br /&gt;
scope는 변수명과 값으로 mapping된 document일 뿐이다.&lt;br /&gt;
이러한 mapping은 실행될 JavaScript 함수의 local scope가 된다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;&lt;SPAN style=&quot;FONT-SIZE: 12pt&quot;&gt;* database reference&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;mongodb는 database reference(DBRefs)를 지원한다.&lt;br /&gt;
이는 URL과 비슷하다.&lt;br /&gt;
document를 unique하게 가리킬 수 있도록 한다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;DBRef란?&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;DBRef는 embeded document로, mongodb의 다른 embeded document와 유사하다.&lt;br /&gt;
DBRef는 그러나 다음과 같이 특별한 키가 포함되어야 한다.&lt;br /&gt;
{&quot;$ref&quot;:collection, &quot;$id&quot;:id_value}&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;DBRef는 특정 collection과 id_value를 참고한다.&lt;br /&gt;
이러한 두개의 정보는 mongodb database 내의 어떤 다른 document들과도 unique id를 부여한다.&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;만약 다른 database를 참고하고 싶다면, $db를 추가하면 된다.&lt;br /&gt;
{&quot;$ref&quot;:collection, &quot;$id&quot;:id_value, &quot;$db&quot;:database}&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;db.A.find()&lt;br /&gt;
{ &quot;_id&quot; : 1, &quot;AKEY&quot; : 1 }&lt;br /&gt;
{ &quot;_id&quot; : 2, &quot;AKEY&quot; : 2 }&lt;br /&gt;
라면,&lt;br /&gt;
db['A'].find()&lt;br /&gt;
{ &quot;_id&quot; : 1, &quot;AKEY&quot; : 1 }&lt;br /&gt;
{ &quot;_id&quot; : 2, &quot;AKEY&quot; : 2 }&lt;br /&gt;
도 가능하다.&lt;br /&gt;
$ref를 받아 db[ref.$ref]로 전달하여 참조된다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;Driver에서 DBRef 지원&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;note = {&quot;_id&quot;: 20, &quot;author&quot;: &quot;kristina&quot;,&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &quot;text&quot;: &quot;... and DBRefs are easy, too&quot;,&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &quot;references&quot;: [DBRef(&quot;users&quot;, &quot;mike&quot;), DBRef(&quot;notes&quot;, 5)]}&lt;br /&gt;
와 같이 pyMongo에서 사용가능하다.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff8b16&gt;DBRef는 언제 사용되는가?&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P style=&quot;MARGIN-LEFT: 4em&quot;&gt;다른 collection에 있는 document의 reference를 저장할 때나,&lt;br /&gt;
driver나 tool의 DBRef 함수를 사용할 수 있는 장점이 있다.&lt;br /&gt;
물론, &quot;_id&quot;를 reference로 사용하는 것이 간단하고 쉽다.&lt;/P&gt;&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-106-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-106-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-fr/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-fr/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
&lt;div class=&quot;tt-plugin tt-share-entry-with-sns tt-sns-icon-alignment-left tt-sns-icon-size-small&quot;&gt;
	&lt;div class=&quot;tt-sns-wrap&quot; id=&quot;ttSnsWrap-&quot;&gt;
		&lt;ul class=&quot;tt-sns-service-default&quot;&gt;
			&lt;li class=&quot;tt-sns-service-mypeople&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('mypeople', '', '');&quot;&gt;마이피플&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-twitter&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('twitter', '', '');&quot;&gt;트위터&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-facebook&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('facebook', '', '');&quot;&gt;페이스북&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-other&quot;&gt;&lt;a href=&quot;javascript:;&quot; onmouseover=&quot;ShareEntryWithSNS.showLayer(event, '');&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;더보기&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
		&lt;ul class=&quot;tt-sns-service-more&quot; id=&quot;ttSnsServiceMore-&quot; onmouseout=&quot;ShareEntryWithSNS.hideLayer(event, '');&quot;&gt;
			&lt;li class=&quot;tt-sns-service-me2day&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('me2day', '', '');&quot;&gt;미투데이&lt;/a&gt;&lt;/li&gt;
			&lt;li class=&quot;tt-sns-service-yozm&quot;&gt;&lt;a href=&quot;javascript:;&quot; onclick=&quot;ShareEntryWithSNS.share('yozm', '', '');&quot;&gt;요즘&lt;/a&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/div&gt;
	&lt;div class=&quot;tt-sns-clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=20784407&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;&lt;div style=&quot;text-align:left; padding-top:10px;&quot;&gt;
&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?href=greenfishblog.tistory.com/106&amp;amp;layout=standard&amp;amp;show_faces=true&amp;amp;width=310&amp;amp;action=like&amp;amp;font=tahoma&amp;amp;colorscheme=light&amp;amp;height=65&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:310px; height:65px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;another_category another_category_color_gray&quot;&gt;
&lt;h4&gt;'&lt;a href=&quot;/category/Research&quot;&gt;Research&lt;/a&gt;&amp;nbsp;&gt;&amp;nbsp;&lt;a href=&quot;/category/Research/mongodb&quot;&gt;mongodb&lt;/a&gt;' 카테고리의 다른 글&lt;/h4&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/108&quot; &gt;[mongodb] Replication&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/107&quot; &gt;[mongodb] Administration&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/106&quot; &gt;[mongodb] Advanced topics&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/105&quot; &gt;[mongodb] Aggregation (MapReduce)&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/104&quot; &gt;[mongodb] Indexing&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;a href=&quot;/103&quot; &gt;[mongodb] Querying&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;(0)&lt;/span&gt;
&lt;/th&gt;
&lt;td&gt;
2011/09/19&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;</description>
			<category>mongodb</category>
			<author>초록생선</author>
			<guid>http://greenfishblog.tistory.com/106</guid>
			<comments>http://greenfishblog.tistory.com/106#entry106comment</comments>
			<pubDate>Fri, 23 Sep 2011 15:39:53 +0900</pubDate>
		</item>
	</channel>
</rss>
