Computer Science/BackEnd

장고 | 장고 공식 문서 내용 정리 #1-3 Getting started : writing your first Django app, part 2

토마토. 2022. 9. 3. 11:36

첫 번째 장고 앱 작성, 2부 | 장고 문서 | 장고 (djangoproject.com)

 

Writing your first Django app, part 2 | Django documentation | Django

Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate

docs.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 관계
    • 어떤 테이블에서 다른 테이블에 하나의 관계를 가지는 것
    • 일부일처제가 대표적인 예시

[DB] 1:1, 1:N, N:M 관계 (velog.io)

  • 1:M 관계
    • 한 쪽 테이블이 관계를 맺은 테이블 쪽의 여러 객체를 가질 수 있는 것
    • 부모는 자식을 1, 2, 3명 그 이상도 가질 수 있지만, 
    • 자식은 부모를 하나만 가질 수 있다. 
    • 이 관계를 표현하기 위해 PK(Primary Key), FK(Foreign Key)를 사용한다. 
    • PK(Primary Key) : 엔티티를 식별할 수 있는 대표키(Unique)
    • FK(Foreign Key) : 다른 테이블의 기본키를 참조, 기본키와 동일한 도메인
    • 부모 테이블의 PK를 자식 테이블에 FK로 집어넣어 관계를 표현한다. 

[DB] 1:1, 1:N, N:M 관계 (velog.io)

  • N:M 관계
    • 양쪽 엔티티 모두에서 1:N 관계를 가지는 것
    • 예를 들면, 학원과 학생의 관계

[DB] 1:1, 1:N, N:M 관계 (velog.io)

참고 : 관계형 데이터베이스 설계 (관계 종류 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에서 간편하게 데이터를 추가/삭제할 수 있다.