mysite/settings.py
는 장고 설정을 모듈 변수로 표현한 보통의 파이썬 모듈이다. 기본적으로는 SQLite를 사용하도록 구성.
먼저 TIME_ZONE을 Asia/Seoul로 수정
INSTALLED_APPS
는 현재 장고 인스턴스에서 활성화된 모든 장고 어플리케이션들의 이름이 담겨 있다. 앱들은 다수의 프로젝트에서 사용될 수 있고, 다른 프로젝트에서 쉽게 사용될 수 있도록 패키징하여 배포할 수 있다.
기본적으로 다음의 앱들을 포함
django.contrib.admin
: 관리용 사이트django.contrib.auth
: 인증 시스템django.contrib.contenttypes
: 컨텐츠 타입을 위한 프레임워크django.contrib.sessions
: 세션 프레잌워크django.contrib.messages
: 메세지이 프레임워크django.contrib.staticfiles
: 정적 파일을 관리하는 프레임워크이러한 기본 어플리케이션들 중 몇몇은 최소한 하나 이상의 데이터베이스 테이블을 사용하는데, 그러기 위해서는 데이터베이스에서 테이블을 미리 만들 필요가 있다. 이를 위해 다음의 명령을 실행한다.
python manage.py migrate
migrate 명령은
INSTALLED_APPS
설정과mysite/settings.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)
데이터베이스의 각 필드는 Field 클래스의 인스턴스로 표현된다(CharField, DateTimeField)
각각의 Field 인스턴스의 이름(question_text, pub_date 등)은 기계가 읽기 좋은 형식의 데이터베이스 필드 이름이다.
위에서 작성한 코드가 장고에게 상당한 정보를 전달한다. 장고는 이 정보들을 가지고 다음과 같은 일을 할 수 있다.
먼저 현재 프로젝트에 polls 앱이 설치되어 있다는 것을 알려야 한다. 앱을 현재 프로젝트에 포함시키려면 앱의 구성 클래스에 대한 참조를 INSTALLED_APPS
에 추가해야 한다. polls/apps.py
파일 내에 존재하는 PollsConfig
클래스를 추가한다
# mysite/settings.py
INSTALLED_APPS = [
...
'polls.apps.PollsConfig',
...
]
python manage.py makemigrations polls
makemigrations
를 실행시킴으로서, 모델을 변경시킨 사실과 이 변경사항을 migration으로 저장시키고 싶다는 것을 django에게 알려준다.
마이그레이션이란?
모델의 변경 내역을 DB 스키마에 적용시키는 장고의 방법
장고는 ORM을 사용하기 때문에 models.py와 클래스를 통해 DB 스키마를 생성하고 컨트롤하게 되는데, 이때 DB 스키마를 git처럼 버전으로 나눠서 관리할수 있게 해주는 시스템
즉, 하나의 마이그레이션 파일은 해당 마이그레이션이 생성된 시점의 모델 구조를 담고 있다.
이제 migrate를 실행시켜 데이터베이스에 모델과 관련된 테이블을 생성한다.
migrate 명령은 아직 적용되지 않은 마이그레이션을 모두 수집해 이를 실행하며 이 과정을 통해 모델에서의 변경 사항들과 데이터베이스의 스키마 동기화가 이루어진다.
마이그레이션은 매우 강력한 기능으로 프로젝트를 개발할 때처럼 데이터베이스나 테이블에 손대지 않고도 모델의 반복적인 변경을 가능하게 해준다. 동작 중인 데이터베이스를 자료 손실 없이 업그레이드 하는데 최적화 되어 있다.
정리하자면, 모델의 변경을 만드는 세 가지 단계는
python manage.py shell
from polls.models import Choice, Question # Import model
Question.obejcts.all()
# <QuerySet []>
from django.utils import timezone
q = Question(question_text="What's new?", pub_date=timezone.now())
q.save()
q.id
q.question_text
# "What's new?"
q.pub_date
# 위에서 timezone을 통해 현재 시간 설정했으므로 설정된 시간 출력됨
q.question_text = "What's up?" # Change value
q.save()
Question.objects.all()
# <QuerySet [<Question: Question object (1)>]>
Question 객체의 상세한 표현을 위해 다음과 같이 수정
# polls/models.py
import datetime
from django.db import models
from django.utils import timezone
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __str__(self):
return self.question_text
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
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):
return self.choice_text
이후 다시 shell 갖고 놀기
>>> from polls.models import Choice, Question
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>
>>> 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?>
>>> Question.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Question matching query does not exist.
>>> Question.objects.get(pk=1)
<Question: What's up?>
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True
# Give the Question a couple of Choices. The create call constructs a new
# Choice object, does the INSERT statement, adds the choice to the set
# of available choices and returns the new Choice object. Django creates
# a set to hold the "other side" of a ForeignKey relation
# (e.g. a question's choice) which can be accessed via the API.
>>> q = Question.objects.get(pk=1)
# Display any choices from the related object set -- none so far.
>>> q.choice_set.all()
<QuerySet []>
# Create three choices.
>>> 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 objects have API access to their related Question objects.
>>> c.question
<Question: What's up?>
# And vice versa: Question objects get access to Choice objects.
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
# Let's delete one of the choices. Use delete() for that.
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()
여기서
choice_set
을 선언하지 않았는데도 가능한 이유?
요약하면, ForeigKey 등을 통해모델 A
를 참조하는모델 B
는 변수를 통해 접근이 가능하고,모델 B
는모델 A
에 접근할 때,모델명_set
의 형태로 접근이 가능하다
즉., 여기서는Choice
의question
변수는Question
모델을 ForeignKey로 참조한다. 따라서q.choice_set
과 같은 접근이 가능해진다
관리자 생성
python manage.py createsuperuser
admin, asdf1234
개발 서버 시작
python manage.py runserver
이후 로그인
관리자 사이트에 들어가기
관리 사이트에서 poll app을 변경가능하도록 만들기
# polls/admn.py
from django.contrib import admin
from .models import Question
admin.site.register(Question)
(마지막에서 편집 에러 나네...)