나의 첫 Django 앱 만들기 - part 2 - 1

이 강좌는 지난 강좌인 나의 첫 Django 앱 만들기 - part 1 - 2 에 이어지는 강좌입니다. 이번 강좌에서는 지난 강좌에서 예고한 바와 같이 데이터베이스를 만들어 보겠습니다. 그 다음, 첫 장고 모델을 만들고, 장고 프로젝트와 함께 자동으로 만들어지는 장고의 강력한 기능인 어드민 사이트에 대해 간단히 알아 보도록 하겠습니다.

데이터베이스 셋업

자 그럼, mysite/settings.py 파일을 편집기로 열어 주십시오. 이 파일은 장고의 메인 셋팅을 대표하는 모듈 레벨 변수들을 포함하는 평범한 파이썬 모듈입니다.

장고의 셋팅스 파일은 디폴트 옵션으로 SQLite 설정을 가지고 있습니다. 만약에 데이터베이스에 대해 잘 모르시거나, 그냥 장고 앱을 빨리 만들어 보고 싶으시다면 이 데이터베이스가 적격 입니다. SQLite은 파이썬에 포함되어 있으므로 SQLite을 사용하기 위해서 별도의 패키지를 설치하지 않으셔도 됩니다. 하지만 실제로 프로젝트를 시작하기 전에는 성능이 좋은 PostgreSQL 과 같은 데이터베이스를 사용하여 프로젝트 개발 중에 데이터베이스를 바꾸는 골치아픈 일을 피하도록 하십시오.

만약에 그 밖에 다른 데이터베이스를 사용하고 싶으시면 적절한 database bindings 를 설치하시고, DATABASES 'default' 안에 있는 다음의 키들을 데이터베이스 커넥션 설정에 맞게 변경하여 주십시오.

  • ENGINE – 자신의 데이터베이스에 맞게 다음 중에 하나를 입력 합니다.
    'django.db.backends.sqlite3''django.db.backends.postgresql','django.db.backends.mysql',  'django.db.backends.oracle'. 다른 백앤드는 여기서 확인하여 주십시오.
  • NAME – 자신의 데이터베이스 이름 입니다. SQLite를 사용 하시면 데이터베이스는 하나의 파일로써 컴퓨터에 저장 됩니다. 이 경우에는 데이터베이스 파일 이름을 포함한 절대 경로 (full absolute path) 가 NAME 키에 들어 갑니다. 디폴트 값인 os.path.join(BASE_DIR, 'db.sqlite3')를 사용하시면 프로젝트 디렉터리안에 데이터베이스 파일이 저장 됩니다.

만약에 SQLite 이외의 다른 데이터베이스를 사용하시면 USERPASSWORD, 와 HOST 등의 키 값이 추가 되어야 합니다. 더 자세한 내용은 DATABASES 를 참조하여 주십시오.

QLite 이외의 데이터베이스 사용 방법

SQLite 이외의 데이터베이스를 사용하고자 하신다면, 사전에 데이터베이스를 설치한 후 데이터베이스를 만드셔야 합니다. 새로운 데이터베이스를 만들기 위해서는 데이터베이스 프로그램의 인터액티브 프롬프트에서 다음의 명령어를 실행하여 주십시오.

"CREATE DATABASE database_name;"

 

또한 mysite/settings.py 에 설정한 데이터베이스 유저에게 “create database” 권한을 주어야 합니다. 그래야 이 강좌의 후반부에 필요한 test database의 자동 생성이 가능합니다.

만약 SQLite을 사용 하신다면, 데이터베이스 파일이 자동으로 생성 되기 때문에 사전에 아무 것도 하지 않아도 됩니다.

mysite/settings.py 파일을 수정하실 때 TIME_ZONE 설정을 하여 주십시오.

필자의 말

"settings.py" 파일에 TIME_ZONE = 'Asia/Seoul'행을 추가하시면 됩니다. 만약 다른 나라의 타임존을 알고 싶으시면 파이썬 쉘에서 다음의 코드를 입력하여 주십시오.

>>> import pytz
>>> pytz.all_timezones

또한 파일 위쪽에 위치한 INSTALLED_APPS 셋팅을 확인하여 주십시오. 이 설정은 장고 인스턴스안에 액티브 상태의 장고 어플리케이션 이름을 담고 있습니다. 앱은 여러개의 프로젝트에서 사용이 가능하고, 패키지로 만들어 다른 사람들의 프로젝트에서 쓰여질 수 도 있습니다.

기본적으로 INSTALLED_APPS은 장고의 하기의 디폴트 앱을 포함하고 있습니다.

이 어플리케이션들은 편리함을 위해 기본적으로 포함되어 있습니다.

이 어플리케이션 중 몇개는 최소 한개 이상의 데이터베이스 테이블을 사용합니다. 따라서 이것들을 사용하기 전에 테이블을 만들 필요가 있습니다. 다음 명령어를 실행하여 주십시오.

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying sessions.0001_initial... OK

migrate 명령어는 셋팅의 INSTALLED_APPS 을 확인하고 mysite/settings.py 파일과 기본 어플리케이션이 가지고 있는 데이터베이스 마이그레이션 파일에 따라 필요한 테이블을 만듭니다. 이 마이그레이션 파일에 대해서는 뒤에서 다루도록 하겠습니다. 명령어를 실행하면 각 마이그레이션에 대한 메세지가 출력 됩니다. 장고가 실제로 데이테베이스에 생성한 테이블을 확인하고 싶으시면 데이터베이스 커맨드라인 클라이언트에서 다음의 명령어를 실행해 보십시오. \dt (PostgreSQL), SHOW TABLES; (MySQL), .schema (SQLite), orSELECT TABLE_NAME FROM USER_TABLES; (Oracle) 

장고 프로젝트의 최소화

위에서 설명했듯이 기본 어플리케이션은 일반 사용을 위해 디폴트로 포함되어 있으나, 모든 사람들이 필요로 하는 것은 아닙니다. 만약에 이중에 필요 없는 것이 있다면 migrate 을 실행하기 전에  INSTALLED_APPS 에서 원하는 라인을 삭제 하거나 주석 처리를 하십시오. migrate 명령어는 INSTALLED_APPS 에 포함된 어플리케이션에 대해서만 마이그레이션을 실행하게 됩니다.

모델 만들기

다음은 메타 데이터를 포함하고 있는 데이터베이스의 레이아웃인 아주 중요한 모델을 정의해 보겠습니다.

장고의 철학

모델은 데이터를 데이터베이스에 저장하기 위한 데이터의 기초입니다. 모델은 저장할 데이터의 중요한 필드와 데이터 형식등을 가집니다. 장고는 DRY Principle 이라는 중복 제거 원리를 따른며, 데이터 모델을 한곳에 정의하고 그 곳에서 모든 것을 만들고자 하는 이념을 가지고 있습니다.

모델은 마이그레션 파일을 포함한다. Ruby On Rails와는 다르게 모델 파일을 통해 마이그레이션 파일을 만듭니다. 기본적으로 이 마이그레이션 파일은 데이터베이스를 모델에 맞춰 업데트를 하기 위한 기록 정도라고 볼 수 있습니다.

우리의 단순한 투표 앱을 위해 Question와 Choice라는 모델을 만들겠습니다. A Question 모델은 질문과 공개 날짜 필드를 가지고 있습니다. Choice 모델은 선택과 투표라는 2개의 필드를 갖습니다. 각 Choice 모델은 하나의 Question 모델과 관계가 있습니다.

이러한 컨셉들은 단순한 파이썬 클래스와 같습니다. polls/models.py 파일을 다음과 같이 수정하여 주십시오.

polls/models.py
from django.db import models


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


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

코드는 아주 간단하며, 각 모델은 django.db.models.Model 모델의 서브 모델입니다. 각 모델은 클래스 변수를 포함하고, 각각의 클래스 변수는 모델 데이터가 저장될 데이터베이스의 필드와 같습니다.

데이터베이스의 필드는 모델 클래스안에 정의되는 Field 클래스의 오브젝트와 같습니다. – e.g.,캐릭터 필드를 위한 CharField, 날짜를 위한 DateTimeField. 이것들이 장고에게 각 필드에 어떤 형식의 데이터가 저장될 것 인지를 알려줍니다.

각 Field 인스턴스의 이름이 데이터베이스의 형식에 맞는 데이터베이스 필드의 이름이 됩니다. (e.g. question_text or pub_date) 당신은 이 이름을 파이썬 코드에서 사용하게 되고, 데이터베이스는 컬럼 이름으로 사용하게 됩니다.

Field 클래스를 정의할 때 첫번째 옵션 인수를 사용하면 필드의 이름을 읽기 어려운 변수 이름을 일기 쉬운 human-readable 이름으로 변경할 수가 있습니다. 실제로 데이터베이스의 필드 이름이 바뀌는건 아니고 어드민 사이트와 같은 곳에 변경되어 출력됩니다. 만약 이 옵션 인수를 사용하지 않은면 장고는 클래스 변수의 이름을 그대로 어드민 사이트와 같은 곳에 출력하여 줍니다. 위의 예제를 보시면 Question.pub_date 오브젝트를 정의할 때만 'date published' 라는 옵션 인수를 전달했고, 나머지 오브젝트의 변수 이름은 충분히 읽기 쉬운 이름이기에 옵션 인수를 사용하지 않았습니다.

어떤 Field 클래스는 필수 인수를 가지고 있습니다. 예를 들어 CharField 클래스와 같은 경우는 max_length라는 필수 인수를 필요로 합니다. 이것은 데이터베이스 스키마에서만 사용되는 것이 아니고, 유저 데이터의 유효성 검사를 할 때 등에도 사용됩니다.

Field 클래스에게는 그 밖에도 여러가지 옵션 인수 전달할 수 있습니다. 위의 예제를 보면 votes 오브젝트에게 default 인수값 0을 전달했습니다.

마지막으로 예제를 보면 ForeignKey를 사용하여 두 클래스간에 관계를 정의한 것을 알 수가 있습니다. 이런식으로 장고에게 각 Choice 클래스가 하나의 Question. 클래스와 관계가 있다는 것을 알려줍니다. 장고는 many-to-one, many-to-many, and one-to-one과 같은 모든 일반 데이터베이스 관계를 지원합니다.

모델 활성화

위의 몇 줄 안되는 모델 코드는 장고에게 아주 많은 정보를 알려 줍니다. 이 코드로 장고는 아래와 같은 것들을 할 수가 있습니다.

  • 이 앱의 데이터베이스 스키마 생성 (CREATE TABLE statements).
  • Question과 Choice 오브젝트에 엑세스 할 수 있는 Python database-access API 생성.

먼저 polls 앱이 프로젝트에 설치되어 있다는 것을 알려줘야 합니다.

장고의 철학

장고 앱은 모듈식입니다. 다른 프로젝트에서 사용할 수도 있으며, 다른 사람들에게 패키지로써 제공할 수도 있습니다.

mysite/settings.py 파일을 다시 수정하겠습니다. INSTALLED_APPS 셋팅에 'polls.apps.PollsConfig'를 다음과 같이 추가하여 주십시오.

mysite/settings.py
INSTALLED_APPS = [
    'polls.apps.PollsConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

이제 장고에게 polls app 가 설치되어 있음을 알려 주었습니다. 다음 명령어를 실행하여 주십시오.

$ python manage.py makemigrations polls

다음과 같이 출력되는 것을 볼 수 있을 겁니다.

Migrations for 'polls':
  polls/migrations/0001_initial.py:
    - Create model Choice
    - Create model Question
    - Add field question to choice

makemigrations, 명령어를 실행하여 장고에게 새로 추가한 파일이나 변경된 파일이 있음을 알려주고, 변경된 내용을 migration 파일로써 저장하도록 합니다.

마이그레션은 모델의 변경내용이 디스크상에 저장되는 단순한 파일입니다. 원한다면 새로 만든 모델의 마이크레이션 파일을 확인할 수도 있습니다. /migrations/0001_initial.py 파일을 열어 보십시오. 걱정하지 마십시오. 마이그레이션을 할 때마다 이 파일을 확인해야 하는 것은 아닙니다. 하지만 필요에 따라 직접 수정하여 사용할 수도 있습니다.

마이그레이션 파일이 만들어 졌지만, 아직 데이터베이스 스키마를 만들지는 않았습니다.  데이터베이스 스키마를 자동으로 관리해주는 명령어 있는데 그것이 migrate 입니다. 조금 뒤에 이 명령어에 대해 살펴보기로 하고, 먼저 이 명령어를 실행하면 어떤 SQL 명령어가 내부적을 실행되는지를 볼도록 하겠습니다. sqlmigrate 명령어는 실제 SQL 명령어를 실행하지는 않고 실행될 내용만을 보여줍니다. 이 명령어는 마이그레이션 이름을 파라메터로 받고 실행될 SQL를 리턴하여 줍니다. 실행하여 보도록 하지요.

$ python manage.py sqlmigrate polls 0001

다음과 같이 출력되는 것을 볼 수 있을겁니다. (보기 좋게 포멧을 한거니, 실제 출력되는 것과는 조금 다를 것입니다.)

BEGIN;
--
-- Create model Choice
--
CREATE TABLE "polls_choice" (
    "id" serial NOT NULL PRIMARY KEY,
    "choice_text" varchar(200) NOT NULL,
    "votes" integer NOT NULL
);
--
-- Create model Question
--
CREATE TABLE "polls_question" (
    "id" serial NOT NULL PRIMARY KEY,
    "question_text" varchar(200) NOT NULL,
    "pub_date" timestamp with time zone NOT NULL
);
--
-- Add field question to choice
--
ALTER TABLE "polls_choice" ADD COLUMN "question_id" integer NOT NULL;
ALTER TABLE "polls_choice" ALTER COLUMN "question_id" DROP DEFAULT;
CREATE INDEX "polls_choice_7aa0f6ee" ON "polls_choice" ("question_id");
ALTER TABLE "polls_choice"
  ADD CONSTRAINT "polls_choice_question_id_246c99a640fbbd72_fk_polls_question_id"
    FOREIGN KEY ("question_id")
    REFERENCES "polls_question" ("id")
    DEFERRABLE INITIALLY DEFERRED;

COMMIT;

Note:

  • 사용하는 데이터베이스에 따라 출력값이 다릅니다. 위의 예는 PostgreSQL을 사용하였을 경우입니다.
  • 테이블 이름은 앱이름 (polls)과 소문자 모델 이름 (question 과 choice) 을 언더 스코어로 연결되어 자동으로 생성됩니다. (원하는 이름으로 변경할 수도 있습니다.)
  • 기본키 - Primary keys (IDs) 는 자동으로 생성됩니다. (이것도 커스터마이징 가능합니다.)
  • 장고는 관습적으로 "_id" 를 외래키 - foreign key 필드 이름에 추가합니다. (이것도 커스터마이징 가능합니다.)
  • 외래키 관계는 FOREIGN KEY constraint에 의해 만들어 집니다. DEFERRABLEparts; 대해서는 걱정하지 마십시오. 그냥 PostgreSQL에게 트랜스액션이 끝날때까지 외래키를 강요하지 말라고 하는 구문입니다.
  • 사용하고 있는 데이터베이스에 따라 구문이 달라지므로, 데이터베이스마다 다른 필드 타입 auto_increment (MySQL), serial (PostgreSQL), integer primary key autoincrement (SQLite)은 자동으로 지정됩니다. 또한, 필드 이름에 싱글 쿼테이션을 쓰여 하는지, 더블 쿼테이션을 써야 하는지도 자동으로 판단합니다.
  • 위에서도 설명했듯이 sqlmigrate 명령어는 실제로 데이터베이스에 마이그레이션을 실행하지는 않습니다. 단순히 장고가 어떤 SQL을 실행할 것인지를 보여줄 뿐입니다. 실제 마이그레이션을 실행하기 전에 SQL을 확인 하거나, 데이터베이스 어드민이 SQL 스크립트를 수정해야 할 때 사용하면 좋습니다.

python manage.py check; 명령어를 실행하면 마이그레이션을 시작하거나 데이터베이스를 변경하기 전에 문제를 체크할 수가 있습니다.

이제 migrate 실행하여 실제 마이그레이션을 하여 데이터베이스에 모델 테이블을 만들어 봅시다.

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
  Rendering model states... DONE
  Applying polls.0001_initial... OK

migrate 명령어는 실행되지 않은 모든 마이그레이션을 적용합니다. (장고는 django_migrations 테이블에 적용된 마이그레이션을 기록하여 모델의 변경된 내용을 데이터베이스 스키마와 싱크해 줍니다.)

이러한 마이그레이션 기능은 프로젝트를 개발하는 중에 데이터베이스나 테이블을 삭제하고 새로 만들 필요 없이 모델을 변경 가능하게 해주는 강력한 기능입니다. 특히 데이터 손실 없이 라이브로 데이터베이스를 업그래이드 하게 도와줍니다. 이 부분에 대해서는 강좌 후반부에서 다루도록 하겠습니다. 지금은 모델을 변경하기 위한 3가지 스텝만을 기억하여 주십시오.

마이그레이션 프로세스를 마이그레이션 파일을 만들고, 마이그레이션을 실행하는 2개의 명령어로 나눈 이유는 버전 컨트롤 시스템을 사용하고 마이그레이션 파일들을 앱고 함께 전달할 수 가 있기 때문입니다. 이것은 개발을 편하게 할 뿐만 아니라, 프로덕션이나 다른 개발자들에게도 유용하게 쓰여집니다.

manage.py 유틸리티에 대해서 더 자세히 알고 싶으시면 django-admin documentation 에서 더 많은 정보를 확인하여 주십시오.

API 사용하기

자, 이제 대화형 파이썬 쉘 (interactive Python shell) 을 통하여 장고가 제공하는 무료 API를 가지고 놀아 보도록 합시다. 다음 명령어를 실행하여 파이썬 쉘을 열어보죠.

$ python manage.py shell

단순히 “python” 명령어를 실행하지 않고 위의 명령어를 실행하는 이유는 manage.py 를 이용하여 DJANGO_SETTINGS_MODULE 의 환경 변수를 셋팅하고 장고에게mysite/settings.py 파일의 파이썬 임포트 패스를 제공하기 위해서 입니다.

Bypassing manage.py

만약 manage.py를 사용하고 싶지 않다면, DJANGO_SETTINGS_MODULE 환경 변수에 mysite.settings 값을 대입한 후, 플래인 파이썬 쉘을 시작하고 장고를 셋업하여 주십시오

$ export DJANGO_SETTINGS_MODULE=mysite.settings
$ python
>>> import django
>>> django.setup()

만약에 AttributeError, 가 발생하면 이 강좌의 장고 버전과 다른 버전을 사용하고 있을 것입니다. 사용하고 있는 장고 버전에 맞는 강좌를 선택하거나 새로운 장고 버전으로 업데이트하여 주십시오.

반드시 python 명령어를 manage.py가 있는 디렉터리에서 실행하거나, 그 디렉터리가 파이썬 패스에 들어 있어야 합니다. 그래야 import mysite가 실행됩니다.

이 부분에 대한 자세한 정보를 원하시면 django-admin documentation을 참조하여 주십시오.

파이썬 쉘에 들어왔으니 database API를 구경해 봅시다.

>>> from polls.models import Question, Choice   # 우리가 만든 모델 클래스를 임포트 합니다.

# No questions are in the system yet.
>>> Question.objects.all()
<QuerySet []>

# 새로운 Question 오브젝트 생성.
# 타임존 서포트가 디폴트 settings 파일에 활성화되어 있으므로,
# pub_date에 datetime.datetime.now()이 아닌
# timezone.now()을 사용하여 tzinfo를 포함하고 있는 datetime을 대입하여 주십시오.
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())

# 위에서 클래스 오브젝트를 생성하였지만 메모리상에만 만든것이고 아직 데이터베이스에 저장되지는 않았습니다.
# save() 명령어를 실행하여 데이터베이스에 저장을 해봅시다.
>>> q.save()

# 이제 오브젝트가 ID를 가진 것을 볼 수 있습니다.
# 데이터베이스에 따라 "1"가 아니고 "1L"를 출력하는 경우가 있습니다.
# 이것은 사용하고 있는 데이터베이스가 integetr를 long integer 오브젝트로 리턴하기 때문이니 아무 문제 없습니다.
>>> q.id
1

# 파이썬 속성을 통해 모델의 필드에 엑세스해 보십시오.
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)

# 파이썬 속성을 변경하여 필드 값을 변경한 후, save() 함수를 실행하여 주십시오.
>>> q.question_text = "What's up?"
>>> q.save()

# objects.all() 클래스 메소드는 데이터베이스에 있는 모든 question 오브젝트를 보여줍니다.
>>> Question.objects.all()
<QuerySet [<Question: Question object>]>

그런데 <Question: Question object> 만으로는 아무 정보를 얻을 수가 없습니다. polls/models.py안의 Question과 Choice 모델에 __str__() 메소드를 추가하여 봅시다.

polls/models.py
from django.db import models


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

    def __str__(self):  # __unicode__ on Python 2
        return self.question_text


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

    def __str__(self):  # __unicode__ on Python 2
        return self.choice_text

모델에 __str__() 메소드를 추가하는 것은 아주 중요합니다. 쉘을 사용할 때의 편리함만을 위한게 아니라, 장고 어드민을 사용하기 위해서입니다.

이 메소드는 평범한 파이썬 메소드입니다. 이번에는 데모를 위해서 커스텀 메소드를 추가하여 봅시다.

polls/models.py
import datetime

from django.db import models
from django.utils import timezone


class Question(models.Model):
    # ...
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

Python 의 datetime 스탠다드 모듈과 django.utils.timezone의 Django의 time-zone-related 유틸리티를 참조하기 위해서 import datetimefrom django.utils import timezone을 각각 추가하였습니다. 만약 피아썬의 time zone handling에 대해서 배우고 싶으시면 time zone support docs을 읽어보기 바랍니다.

수정한 파일을 저장하고 다음 명령어를 실행하여 새로운 파이썬 인터액티브 쉘을 시작하여 봅시다.

$ python manage.py shell

쉘에서 다음의 명령어를 실행하여 봅시다.

>>> from polls.models import Question, Choice

# 조금 전에 추가한 __str__() 메소드가 출력한 내용을 확인하십시오.
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>

# 장고는 키워드 인수를 이용한 강력한 데이터베이스 검색 API 를 제공합니다.
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith='What')
<QuerySet [<Question: What's up?>]>

# 올해 개제된 질문을 검색해봅시다.
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>

# 존재하지 않는 ID를 검색하면 에러 메세지가 출력됩니다.
>>> Question.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Question matching query does not exist.

# 데이터베이스의 기본키로 검색하는 것이 가장 보편적이기에
# 장고는 기본키 검색 쇼트컷 (shortcut) 을 제공합니다.
# 밑의 코드는 Question.objects.get(id=1)와 같습니다.
>>> Question.objects.get(pk=1)
<Question: What's up?>

# 이번에는 우리가 만든 커스텀 메소드가 잘 실행되는지 확인합시다.
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True

# Question에 2개의 Choice를 추가해보죠. create 콜은 새로운 Choice 오브젝트를 만들고,
# 데이터베이스의 INSERT 구문의 역할을 하며, 새로운 choice를 기존의 choice 세트에 추가 하고,
# 새로 만든 Choice 오브젝트를 리턴합니다. (한 문장이 엄청 기네요;;)
# 장고는 외래키 관계의 반대편 오브젝트의 세트를 가지고 있습니다.
# (e.g. question이 가지고 있는 choice 세트) 이것들은 API를 통해 액세스할 수 있습니다.
>>> q = Question.objects.get(pk=1)

# 기본키가 1인 Question 오브젝트가 관계하고 있는 choice 세트를 출력해 봅시다. -- 아직 아무것도 없습니다.
>>> q.choice_set.all()
<QuerySet []>

# 3개의 choice를 추가해보죠.
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)

# Choice 오브젝트는 자신이 관계하고 있는 Question 오브젝트에 액세스할 수 있는 API를 가지고 있습니다.
>>> c.question
<Question: What's up?>

# 반대로 Question 오브젝트도 Choice 오브젝트에 액세스할 수 있는 API를 가지고 있습니다.
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3

# API는 자동으로 모든 관계를 추적합니다.
# 더블 언더스코어를 사용하여 관계를 연결합니다.
# 이것은 제한 없이 원하는 만큼 연결할 수 있습니다.
# pub_date가 올해인 모든 Choice 오브젝트를 검색하여 봅시다.
# (위에서 만든 변수인 'current_year'를 다시 사용합시다.
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>

# delete()을 사용하여 이 중 하나의 choice를 삭제해 보죠.
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()
(1, {u'polls.Choice': 1})
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>]>

모델 관계에 대해서 더 알고 싶다면 Accessing related objects를 읽어 주십시오. 더블 언더스코어를 사용한 API 필드 검색에 대해서 더 자세히 알고 싶으시다면 Field lookups를 읽어 주십시오. 데이터베이스 API에 대해서 알고 싶으시다면 Database API reference읽어 주십시오.

다음 강좌에서는 장고의 강력한 기능인 어드민 사이트에 대해서 알아보도록 하겠습니다.


blog comments powered by Disqus