첫 번째 장고 앱 작성, 2부 | 장고 문서 | 장고 (djangoproject.com)
첫 장고 앱 만들기 #2
데이터베이스 설정
이 문서에서는 SQLite를 사용한다.
SQLite를 사용하지 않는다면, User, Host 같은 것들을 설정해주어야 한다.
SQLite를 사용한다면 다른 건 할 필요가 없다.
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
Installed_apps 설정에는 Django에서 활성화되는 응용 프로그램의 내용을 포함한다.
- 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 설정을 보고, 파일의 데이터베이스 설정과 데이터 마이그레이션에 따라 데이터베이스 테이블을 만들어준다.
(installed_apps의 앱에 대해서만 migrate를 실행해준다.)
모델 만들기
데이터베이스 레이아웃, 메타 데이터를 사용하여 모델을 정의해주자.
장고는 DRY(Don't Repeat Yourself) 원칙을 따른다. 하나의 데이터/개념은 한 곳에만 있어야 한다.
이에 따라 모델은 데이터에 대한 유일한 원천이 되어야하며, 모델에는 모든 필수 필드와 메소드가 정의되어야 한다.
poll 앱에서는 Question과 Choice라는 두 가지 모델을 만든다.
from django.db import models
# Create your models here.
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)
Question, Choice 모델은 django.db.models.Model 클래스를 상속 받아 만든다.
클래스 내부에 있는 변수는 데이터베이스 필드를 나타낸다.
각 피드는 Field 클래스의 인스턴스로,
각 필드가 가지고 있는 데이터 타입을 보여준다(CharField, DateTimeField, IntegerField 등).
각 변수를 데이터베이스 열 이름으로 사용한다. (question_text, pub_date, question, choice_text, votes)
Field 클래스에는 필수 인수/선택 인수가 있다. ex. CharField는 max_length가 필수 인수
ForeignKey는 관계를 정의할 때 사용하는 것이다. 장고가 다른 것과 어떤 관련이 있는지를 알려준다.
다대다, 다대일, 일대일 관계 등이 있다.
- 1:1 관계
- 어떤 테이블에서 다른 테이블에 하나의 관계를 가지는 것
- 일부일처제가 대표적인 예시
- 1:M 관계
- 한 쪽 테이블이 관계를 맺은 테이블 쪽의 여러 객체를 가질 수 있는 것
- 부모는 자식을 1, 2, 3명 그 이상도 가질 수 있지만,
- 자식은 부모를 하나만 가질 수 있다.
- 이 관계를 표현하기 위해 PK(Primary Key), FK(Foreign Key)를 사용한다.
- PK(Primary Key) : 엔티티를 식별할 수 있는 대표키(Unique)
- FK(Foreign Key) : 다른 테이블의 기본키를 참조, 기본키와 동일한 도메인
- 부모 테이블의 PK를 자식 테이블에 FK로 집어넣어 관계를 표현한다.
- N:M 관계
- 양쪽 엔티티 모두에서 1:N 관계를 가지는 것
- 예를 들면, 학원과 학생의 관계
참고 : 관계형 데이터베이스 설계 (관계 종류 1:1 / 1:M / N:M ) - 하나몬 (hanamon.kr)
모델 활성화
모델 활성화하기.
작은 코드로도 장고 데이터베이스 스키마에 접근할 수 있다.
그 전에 해야할 것 1. polls 앱 시작하기
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
이제 polls 모델의 migrations을 실행해준다.
makemigrations가 해주는 기능 : 변경사항을 마이그레이션으로 저장해준다.
$ python manage.py makemigrations polls
Migrations for 'polls':
polls/migrations/0001_initial.py
- Create model Question
- Create model Choice
데이터베이스 스키마를 자동으로 관리하는 명령 sqlmigrate
실제로 migrate하는 게 아니라, SQL 장고가 필요하다고 생각하는 걸 볼 수 있도록 화면에 보여준다.
$ python manage.py sqlmigrate polls 0001
BEGIN;
--
-- Create model Question
--
CREATE TABLE "polls_question" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "question_text" varchar(200) NOT NULL, "pub_date" datetime NOT NULL);
--
-- Create model Choice
--
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL, "question_id" bigint NOT NULL REFERENCES "polls_question" ("id") DEFERRABLE INITIALLY DEFERRED);
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");
COMMIT;
이제 제대로 migrate를 통해 테이블을 생성해준다.
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
Applying polls.0001_initial... OK
테이블을 삭제하거나 새 테이블을 만들지 않아도 모델을 변경할 수 있다.
실시간 업그레이드 가능
API 다루기
$ python manage.py shell
Python 3.8.10 (default, Jun 22 2022, 20:18:18)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
파이썬 shell을 실행해주자.
# polls 앱의 Choice, Question 모델을 불러오기
>>> from polls.models import Choice, Question
# 모델의 모든 객체를 불러온다.
>>> Question.objects.all()
<QuerySet []>
>>> Choice.objects.all()
<QuerySet []>
# Question 필드의 타입에 맞게 timezone을 불러와주자
>>> from django.utils import timezone
# 새로운 객체 생성
>>> q = Question(question_text="What's new?", pub_date=timezone.now())
# 저장
>>> q.save()
# 객체 필드 확인
>>> q.id
1
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2022, 9, 3, 2, 17, 3, 196059, tzinfo=<UTC>)
# 객체 업데이트
>>> q.question_text="what's up?"
>>> q.save()
# 다시 모든 객체 확인
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>
이때 마지막 부분에서 <Queryset [<Question: Question object (1)>]> 이라는 표현은 직관적으로 객체 값을 확인하기 어렵기 때문에, 모델을 리턴하는 방식을 바꾸어주자.
이는 models.py 파일에서 def __str__(self)를 추가해주면 가능하다
from django.db import models
# Create your models here.
class Question(models.Model):
def __str__(self):
return self.question_text
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
def __str__(self):
return self.choice_text
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
이전까지는 필드만 만들어주었다면, 이제 사용자 정의 매소드까지 추가해보자.
from django.db import models
from django.utils import timezone
import datetime
# Create your models here.
class Question(models.Model):
def __str__(self):
return self.question_text
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
was_published_recently 매소드를 이용해서, pub_date가 지금 시간으로부터 하루를 넘지 않은 객체를 return 해주었다.
# polls 앱에서 Choice, Question 모델을 불러온다
>>> from polls.models import Choice, Question
# Question __str__ 매소드로 표현 방식이 달라졌다
>>> 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?>]>
# timezone을 이용한 필터링
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: what's up?>
# was_published_recontly 매소드의 사용법
>>> Question.objects.get(pk=1)
<Question: what's up?>
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True
# Question에 연결되는 choice 모델을 추가하기
>>> q = Question.objects.get(pk=1)
>>> q.choice_set.all()
<QuerySet []>
>>> q.choice_set.all()
<QuerySet []>
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text='sky', votes=1)
<Choice: sky>
>>> c = q.choice_set.create(choice_text='hacking', votes=0)
# 생성한 choice 객체의 개수를 세기
>>> c.question
<Question: what's up?>
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: sky>, <Choice: hacking>]>
>>> q.choice_set.count()
3
# choice 삭제
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: sky>, <Choice: hacking>]>
>>> c = q.choice_set.filter(choice_text__startswith='hac')
>>> c.delete()
(1, {'polls.Choice': 1})
장고 관리자 만들기
다음 명령어로 admin 관리자를 생성해준다.
$ python manage.py createsuperuser
Username (leave blank to use 'tomato'):
Email address: @naver.com
Password:
Password (again):
Superuser created successfully.
그리고 admin 사이트에서 설문조사 앱의 모델을 수정할 수 있도록 설정해준다.
from django.contrib import admin
from .models import Question, Choice
# Register your models here.
admin.site.register(Question)
admin.site.register(Choice)
이제 localhost:8000/admin에서 간편하게 데이터를 추가/삭제할 수 있다.