TIL | Django - 프로젝트 시작하기2

송치헌·2021년 8월 13일
0

TIL | Wecode - Django

목록 보기
2/18
post-thumbnail

이 프로젝트는 장고 공식 홈페이지에 올라온 첫 번째 장고 앱 작성하기, part 2 를 보고 작성한다.

무엇을 배웠는가

데이터베이스 설치

Python에는 기본적으로 SQLite가 제공된다. 따라서 별도로 데이터베이스를 설치할 필요가 없다. 다만 다른 데이터베이스를 사용하고 싶다면 첫 번째 장고 앱 작성하기, part 2 여기에 들어가서 가장 첫단에 데이터베이스 설치 부분을 읽고 따라하면 좋을 것 같다.

migration

데이터베이스계의 Git이라고 보면 될 것 같다.

Git은 버전을 관리해주는 시스템(VCS, Version Controll System)인데 migration도 비슷한 역할을 한다.

다음 명령어를 터미널에 입력해보자.

python manage.py migrate

데이터베이스에 테이블을 만드는 역할을 한다. 마법같은 일이 벌어지면서 우리도 모르게 테이블을 정의한다.

Model 만들기

데이터베이스와 관련된 모듈은 model.py에 명세되어 있다. 일단 이 프로젝트는 따라하는 것에 의의를 두기 때문에 정확한 설명은 따로 포스팅을 할 것이다.

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)

model파일에는 테이블을 클래스로써 저장하여 관리한다.

첫번째, class Question부분에서 question_text필드는 Character형이고 최대 길이는 200까지이다.
DateTimeField는 말 그대로 날짜와 시간 필드를 뜻한다.

두번째, class Choice 부분은 답을 선택하는 것에 대한 테이블을 나타내고 있는데 Question테이블과 관계를 가지고 있다. question에서 ForeignKey로 Question을 가리키고있다.

장고에서는 테이블을 만들면 자동으로 id값을 만들어 주기 때문에 id끼리 자동으로 PK, FK로 매핑이 되었다.

모델의 활성화

Django에서는 Model파일에 든 정보를 가지고 데이터베이스 스키마를 생성한다. 그리고 Question과 Choice 객체에 접근하기 위한 Python 데이터베이스 접근 API를 생성한다.

그러나 이 프로젝트에게 polls앱이 설치되어 있다는 것을 알려야 한다.

앱을 프로젝트에 포함시키기 위해서는 클래스의 참조에 대한 내용을 INSTALLED_APPS 설정에 추가해 주면 된다. INSTALLED_APPS 설정은 mysite/settings.py에서 바꿀 수 있다.

참고로 PollsConfig클래스는 polls/apps.py 파일 안에 존재한다. 이걸 파이썬의 경로로 표현하면 polls.apps.PollsConfig로 표현할 수 있다. 따라서 이 경로를 mysite/settings.pyISTALLES_APPS에 추가해주면 된다.

# 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',
]

이제 Django에서 이 polls앱이 프로젝트에 포함되어 있다는 것을 알게 되었다. 이제 이 수정 사항들을 저장해보자.

python manage.py makemigrations polls

다음과 같이 뜨면 성공

Migrations for 'polls':
  polls/migrations/0001_initial.py
    - Create model Question
    - Create model Choice

makemigrations를 실행시키면서 Django에게 변경사항을 migration으로 저장하고 싶다는 것을 알린 것이다.

자동으로 데이터베이스 스키마를 관리해주는 명령어인 migrate를 알아보자. 그 전에 실행할 SQL문을 보여주는 sqlmigrate명령어로 어떤 쿼리어를 실행할지 살펴보자.

python manage.py sqlmigrate polls 0001

다음과 같이 뜰 것이다.

BEGIN;
--
-- 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
);
--
-- Create model Choice
--
CREATE TABLE "polls_choice" (
    "id" serial NOT NULL PRIMARY KEY,
    "choice_text" varchar(200) NOT NULL,
    "votes" integer NOT NULL,
    "question_id" integer NOT NULL
);
ALTER TABLE "polls_choice"
  ADD CONSTRAINT "polls_choice_question_id_c5b4b260_fk_polls_question_id"
    FOREIGN KEY ("question_id")
    REFERENCES "polls_question" ("id")
    DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");

COMMIT;

참고사항

(*)표시가 있는 부분은 재정의(override)가능

  • 사용하는 데이터베이스에 따라 결과가 다를 수 있음
  • 테이블 이름은 앱 이름과 모델의 이름이 조합되어 자동으로 생성(소문자로 조합) (*)
    polls + Question => polls_question
    polls + Choice => polls_choice
  • 기본키(ID) 자동으로 생성 (*)
  • 외래 키 필드명에 _id를 자동으로 추가 (*)

이제 저장된 변경 사항들을 기준으로 데이터베이스를 생성하면 된다.

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

API 사용

파이썬 쉘을 이용하여 데이터베이스 API를 확인해보자.

python manage.py shell

쉘에 진입했으면 따라서 써보자.

>>> from polls.models import Choice, Question  # polls.models에서 Choice, Question 클래스를 가져온다.

# 아직 아무런 질문이 있지 않다.
>>> Question.objects.all()
<QuerySet []>

# 그럼 새로운 질문을 만들어보자.
# 기본 설정 파일에서 표준 시간대를 지원하므로 Django는 pub_date에 대한 tzinfo가 포함된 datetime을 예상한다.
# datetime.datetime.now() 대신 timezone.now()로 사용하면 제대로 작동할 것이다.
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())

# 객체를 데이터베이스 안에 저장한다. save()를 꼭 써줘야 한다.
>>> q.save()

# 그럼 이제 id가 생긴다.
>>> q.id
1

# 저장한 데이터베이스에서 객체에 대한 값을 반환해보자.
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<Asia/Seoul>) #이 부분은 UTC 표준 시간대 값을 Asia로 바꾼 것이다.

# 값을 바꾸고 저장해보자.
>>> q.question_text = "What's up?"
>>> q.save()

# objects.all()은 데이터베이스 안의 질문들을 모두 보여준다.
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>

마지막 줄에 <Question: Question object (1)>은 객체를 표현하는 데 별로 도움이 되지 않는다고 한다. polls/models.py파일의 Question 모델을 수정하여 __str__()메소드를 Question과 Choice에 추가해 보자.

# polls/models.py
from django.db import models

class Question(models.Model):
	# ...
    def __str__(self):
        return self.question_text
        
class Choice(models.Model):
    # ...
    def __str__(self):
        return self.choice_text

또, 이 모델에 커스텀 메소드도 추가해보자.

# 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 manage.py shell을 실행해서 다음을 확인하자.

>>> from polls.models import Choice, Question

# Make sure our __str__() addition worked.
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>

# Django provides a rich database lookup API that's entirely driven by
# keyword arguments.
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith='What')
<QuerySet [<Question: What's up?>]>

# Get the question that was published this year.
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>

# Request an ID that doesn't exist, this will raise an exception.
>>> Question.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Question matching query does not exist.

# Lookup by a primary key is the most common case, so Django provides a
# shortcut for primary-key exact lookups.
# The following is identical to Question.objects.get(id=1).
>>> Question.objects.get(pk=1)
<Question: What's up?>

# Make sure our custom method worked.
>>> 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

# The API automatically follows relationships as far as you need.
# Use double underscores to separate relationships.
# This works as many levels deep as you want; there's no limit.
# Find all Choices for any question whose pub_date is in this year
# (reusing the 'current_year' variable we created above).
>>> 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()

관리자 생성

python manage.py createsuperuser

원하는 username 입력 후 엔터

Username: admin
Email address: admin@example.com

비밀번호 입력 후 엔터

Password: **********
Password (again): *********
Superuser created successfully.

이제 런서버를 하고 admin페이지로 이동해보자.

python manage.py runserver

http://127.0.0.1:8000/admin/으로 들어가서 방금 설정한 계정에 로그인하면 된다.

# polls/admin.py
from django.contrib import admin

from .models import Question

admin.site.register(Question)

polls의 admin파일에 들어가서 다음과 같이 수정하면 관리 사이트에서 poll app을 변경 가능하도록 만들 수 있다.

Question을 등록했기 때문에 장고에서는 이를 인식하고 관리자 페이지에 표시하게 된다.

part2 끝


어디에 적용했는가

part1과 마찬가지로 이번에는 설문조사 앱인 polls앱을 만들어서 적용시켜 보았다.

어려웠던 점은 무엇인가

이번 파트는 작성해야할 것이 많아서 힘들었다. 따라하는 것이기 때문에 어려운 점은 없었지만 이해하려고 보니 이해가 잘 되지 않았다.

profile
https://oraange.tistory.com/ 여기에도 많이 놀러와 주세요

0개의 댓글