웹/Django

첫 번째 장고 앱 작성하기, part ② (Django 문서 참고)

#fdd4ff 2021. 9. 22. 04:03

* 참고 문서

Django 공식 문서: https://docs.djangoproject.com/ko/3.2/intro/tutorial02/

 

첫 번째 장고 앱 작성하기, part 2 | Django 문서 | Django

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

docs.djangoproject.com

점프 투 장고 : https://wikidocs.net/70650

 

2-02 모델

`[완성 소스]` : [github.com/pahkey/djangobook/tree/2-02](https://github.com/pahkey/djangobook/tree/2 ...

wikidocs.net

 

 


| 목차

 1. 데이터베이스 설치
 2. 모델 만들기
 3. 모델의 활성화
    3-1 INSTALLED_APP 설정
    3-2 migrations
    3-3 sqlmigrate
    3-4 migrate
    3-5 모델 변경을 만드는 단계
 4. API 가지고 놀기
 5. 관리자 생성하지
 6. 개발 서버 시작
 7. 관리자 사이트에 들어가기
 8. 관리자 사이트에서 poll app을 변경가능하도록 만들기
 9. 자유로운 관리 기능을 탐색하기 


 

1. 데이터베이스 설치

 

mysite/settings.py 파일을 열어본다. 이 파일은 Django 설정을 모듈 변수로 표현한 보통의 Python 모듈이며 기본적으로는 SQLite을 사용하도록 구성되어 있다. SQLite를 사용한다면 데이터베이스 파일은 필요할 때마다 자동으로 생성되기 때문에 미리 생성할 것이 없다.

점프 투 장고에 따르면 개발시에는 SQLite를 사용하여 빠르게 개발하고. 실제 운영 시스템은 좀 더 규모 있는 DB를 사용하는 것이 일반적인 개발 패턴이라고 한다. 

(공식문서에 나와있는대로 SQLite를 사용할 것이므로 데이터베이스 설치 부분은 넘어가도록 하겠다. 다른 데이터베이스 사용 부분은 따로 포스팅을 할 예정이다.)

 

python manage.py runserver 명령어 실행시 나오는 문구를 보면 

You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions. 

=> 18개의 적용되지 않은 migration들이 있다고 함. admin, auth, contenttypes, sessions 앱들 (장고 프로젝트 생성시 기본적으로 설치되는 앱들 => config/setting.py 파일에서 확인 가능)과 관련된 내용이며 이것을 적용하려면 python manage.py migrate를 실행해야한다고 함 

=> admin, auth 등과 같은 기본 어플리케이션들 중 몇몇은 최소한 하나 이상의 데이터베이스 테이블을 사용하기 때문에 데이터 베이스에서 테이블을 하나 만들어야하기 때문 (데이터베이스가 필요한 앱만 migration이 필요)

=> 테이블은 데이터 베이스에서 데이터를 저장하기 위한 데이터 집합의 모임이다.

 

python manage.py migrate 을 입력하면 다음과 같다.

=> migrate를 수행하면 admin, auth, contenttypes, sessions 앱들이 사용하는 테이블들이 생성된다. 

 

 

 

 

 

admin, auth, contenttypes, sessions 앱들이 있음을 확인할 수 있다. 만약 필요없는 어플리케이션이 있을 경우 주석처리 하거나 삭제를 하면 된다고 한다. 

 

1. django.contrib.admin – 관리용 사이트.
2. django.contrib.auth – 인증 시스템.
3. django.contrib.contenttypes – 컨텐츠 타입을 위한 프레임워크.
4. django.contrib.sessions – 세션 프레임워크.
5. django.contrib.messages – 메세징 프레임워크. (데이터 베이스와 상관 X)
6. django.contrib.staticfiles – 정적 파일을 관리하는 프레임워크. (데이터 베이스와 상관 X)

=> migrate 명령은 INSTALLED_APPS 에 등록된 어플리케이션에 한하여 실행된다. 

 

사용하는 데이터 베이스에 대한 정보도 정의가 되어 있음을 볼 수 있다. 

=> 데이터베이스 엔진django.db.backends.sqlite3 라고 정의되어있으며, 데이터베이스 파일BASE_DIR 디렉터리 (프로젝트 디렉터리를 의미, 여기서 프로젝트 BASE_DIR은 C:\projects\mysite 를 뜻한다) 밑에 db.sqlite3 파일에 저장한다고 정의되어 있다.

 

 

 


 

2. 모델 만들기

 

모델이란 부가적인 메타데이터를 가진 데이터베이스의 구조(layout)를 말한다. 

설문조사 앱에서 두 가지 모델을 만든다 : Question(질문, 발표일 ), Choice (선택 본문, 투표 집계). 각 Choice는 Question과 연관되어 있다. 

 

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)

CharField( ) => 글자수의 길이가 제한된 텍스트CharField( )를 사용해야 한다 제목은 최대 200자까지 가능하도록 max_length=200을 설정. (cf. 내용(content)처럼 글자수를 제한할 수 없는 텍스트는 TextField( )를 사용. )

DateTimeField( ) => 작성일시처럼 날짜와 시간에 관계된 속성은 DateTimeField를 사용해야 한다.

ForeignKey( ) => Choice 모델은 Question 연관되어 있으므로, Question 모델을 속성으로 가져가야 한다. 기존 모델을 속성으로 연결하려면 ForeignKey를 사용해야 한다. ForeignKey는 다른 모델과 연결하기 위해 사용한다. on_delete=models.CASCADE의 의미는 이 답변과 연결된 질문(Question)이 삭제될 경우 Choice도 함께 삭제된다는 의미이다.

 

 

 


 

3. 모델의 활성화

 

models.py에 대한 코드가 django에게 많은 양의 정보를 전달

=> django는 이 정보를 가지고

1. 앱을 위한 데이터베이스 스키마 생성 (CREATE TABLE문)

2. Question과 Choice 객체에 접근하기 위한 Python 데이터베이스 접근 API를 생성

 

가장 먼저 현재 프로젝트에게 polls 앱이 설치되어 있다는 것을 알려줘야 함.

=> 앱의 구성 클래스에 대한 참조를 INSTALLED_APPS 설정에 추가하면 된다. (테이블 생성을 위해 추가한 것이다.)

 

 

3-1 INSTALLED_APP 설정

(PollsConfig 클래스는 polls/apps.py 파일내에 존재 => 경로: 'polls.apps.PollsConfig')

*polls.apps.PollsConfig는 polls 앱 생성시 자동으로 만들어지는 파일로 따로 만들 필요가 없다. 

이렇게 해서 Django는 polls 앱이 포함된 것을 알게 된다. 

내 경우에는 'polls.apps.PollsConfig' 다음에 ' , ' 를 붙이지 않아서 계속 에러나서 몇 분간 헤맸었다. 저같은 실수는 하지마시길..

 

 

(모델이 신규로 생성되거나 변경되면 makemigrations 명령을 먼저 수행한 후에 migrate 명령을 수행해 주어야 한다.)

* makgemigrations 명령은 실제 테이블 생성을 하지 않으며, 장고가 테이블 작업을 수행하기 위한 작업파일 (ex: 0001_initial.py)을 생성하는 명령어이다. 실제 테이블 생성은 migrate 명령을 통해서만 가능하다.

 

3-2 migrations

$ python manage.py makemigrations polls

makemigrations 명령은 모델을 생성하거나 모델에 변화가 있을 경우에 실행해야 하는 명령어인데, 실행해보면 이와 같은 결과 화면이 나올 것이다. 

makemigrations 을 실행시킴으로서, 우리가 모델을 변경시킨 사실과(이 경우에는 새로운 모델을 만들었다) 이 변경사항을 migration으로 저장하고 싶다는 것을 Django에게 알려준다.

 

위 명령이 수행된 이후 0001_inital.py 라는 파일이 생긴 것을 발견할 수 있음

 

 

 

3-3 sqlmigrate

sqlmigrate 명령은 migration 이름을 인수로 받아 실행하는 SQL 문장을 보여준다. (sqlmigrate 명령은 단지 실행되는 쿼리만 조회할 뿐이다. 실제 쿼리가 수행되지는 않는다.)

$ python manage.py sqlmigrate polls 0001

1. 사용하는 데이터베이스에 따라서 출력결과는 다를 수 있다.

2. 테이블 이름앱의 이름모델의 이름(소문자)이 조합되어 자동으로 생성된다. 이 경우, 앱의 이름인 polls 와 소문자로 표기된 모델의 이름인 question 과 choice가 합쳐진다. (polls + Question = polls_question , polls+Choice=polls_choice) (*override하여 수정할 수 있음)

3. 기본 키(ID)가 자동으로 추가된다. (역시 이 동작도 재지정할 수 있다.)

4. Django는 외래 키 필드명에 "_id" 이름을 자동으로 추가한다. (물론 이것도 재지정할 수 있다.)

5. 사용하는 데이터베이스에 따라, 데이터베이스 고유의 필드타입이 조정된다.

 

 

 

3-4 migrate

migrate 명령어를 실행시켜 데이터베이스에 모델과 관련된 테이블을 생성한다. 

$ python manage.py migrate

 

 

3-5 모델의 변경을 만드는 단계 

1. models.py에서 모델을 변경

2. python manage.py makemigrations 을 통해 이 변경사항에 대한 migration을 만든다.

3. python manage.py migrate 명령을 통해 변경사항을 데이터베이스에 적용한다. 

 

 


 

4. API 가지고 놀기

 

*장고 셸을 통해 모델 사용법을 익혀볼 수 있다.(* 장고 shell은 장고에 필요한 환경들이 자동으로 설정되어 실행된다.)

python manage.py shell
>>> from polls.models import Choice, Question 
# 우리가 쓸 클래스 모델을 import 해준다. 

>>> Question.objects.all() # 아직 시스템 안에 question이 들어있지 않다.
<QuerySet []>

 

timezone 을 import 하여 timezone.now( )라는 함수를 통해 pub_date라는 변수에 현재 시간대를 넣어준다.

>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())
>>> q.save()

객체 q를 생성한 후 save( )함수를 실행하면 Qustion 데이터가 1건 생성된다.

 

>>> q.id
1

데이터가 1건 생성되면 id 값이 생성된다. 데이터를 생성될 때마다 id 값은 1씩 증가된다.

 

 

대입한 값이 제대로 나오는지 확인할 수 있는 결과창이다. 또한, 보이는 것과 같이 question_text 를 변경할 수도 있다. 변경하고 나서는 반드시 save() 함수를 사용해주어야 한다. 게임같은 것도 보면 save가 제일 중요한 것처럼..

 

저장한 Question 모델의 데이터는 Question.objects 를 통해서 조회할 수 있다. 

Question.objects.all( )은 모든 Question 데이터를 조회하는 함수이다.

결과값으로는 QuerySet 객체가 리턴되는데 Question object (1) 에서 1은 Question 데이터의 id 값이다. (위 캡쳐 본은 내가 미리 함수를 건드렸기때문에 question_text가 나오는데, 원래 결과값은 <QuerySet [<Question: Question object (1)> 이 나온다.) 

이 때, Question 모델에 __str__ 메서드를 추가하면 id 값 대신 제목을 표시할 수 있다.

 

 

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

Django 공식 문서에 따르면 __str( )__ 메소드의 추가 이유는 객체의 표현을 대화식 프롬프트에서 편하게 보려는 이유 말고도, Django 가 자동으로 생성하는 관리 사이트 에서도 객체의 표현이 사용되기 때문이라고 한다. 

 

 

그러면 다음과 같은 결과화면을 볼 수 있다.

 

 

 

 

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)

Django 문서에 나온 것처럼 다음과 같이 메소드를 커스텀한다. 

 

>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.get(id=1)
<QuerySet [<Question: What's up?>]>

filter를 사용하여 id 값이 1인 Quesiton 데이터를 조회한다는 뜻이다. id는 유일한 값이므로 filter 대신 get으로도 조회할 수도 있다.

대신 filter를 사용하면 Question의 모든 데이터를 불러오지만, get은 한 건의 데이터만 가져오게 된다. 그러므로 get은 반드시 1건의 데이터를 조회할 때 사용한다.

 

 

 

 

 

 

밑은 Django 공식문서에 적혀있는 실습코드이다. 한번 같이 실행해보면서 결과가 어떻게 나오는지 보면 좋을 것같다.(이 때, 언더바의 갯수가 1개가 아닌 2개인 경우도 있는데 주의해서 작성하자.  내가 그걸 모르고 5번이나 똑같이 안되는 명령어를 치고있었다..)

>>> 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()

 

 

 

 

 


 

5. 관리자 생성하기

 

$ python manage.py createsuperuser

원하는 username 을 입력하고 엔터를 누른다.

Username: admin

원하는 이메일 주소를 입력하라는 메시지가 표시된다.

Email address: admin@example.com

암호를 입력한다. (암호는 확인 차로 두번 물어봄)

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

 

 

 

 


 

6. 개발 서버 시작

 

python manage.py runserver 명령어를 통해 개발 서버를 켠다. http://127.0.0.1:8000/admin/으로 접근할 수 있는데, 그럼 다음과 같이 로그인 화면이 보이게 된다. 

 


 

7. 관리자 사이트에 들어가기

 

앞서 생성한 superuser 계정으로 로그인하게 되면 Django 관리 인덱스 페이지가 보일 것이다. 

 

 


 

8. 관리자 사이트에서 poll app을 변경가능하도록 만들기

 

* polls/admin.py

from django.contrib import admin

from .models import Question

admin.site.register(Question)

Question 을 등록시켜 관리 인덱스 페이지에 보이도록 한다.

 


 

9. 자유로운 관리 기능을 탐색하기

 

Questions 클릭하면 다음과 같은 페이지를 볼 수 있다.

 

4번 실습에서 만들어놨던What's up?Question이 있음을 볼 수 있다.《What’s up?》 질문을 클릭하여 수정한다. 《What’s up?》을 클릭하면 다음과 같은 화면이 나온다. 

 

 

이 서식은 Question 모델에서 자동으로 생성되었다.

Date published 의 값을 바꾼 후 저장 및 편집 계속을 누른다. 그런 후, 우측 상단의 히스토리 버튼을 누르면 Django 관리 사이트를 통해 누가 언제 무엇을 바꾸었는지 목록 확인이 가능하다.

 

결과 화면은 다음과 같다.

 

 

모델 API와 관리 사이트에 익숙해졌다면,part 3에서 투표 앱에 뷰를 추가하는 방법을 배워볼 예정이다.

 

 


 

이렇게 최대한 장고문서를 따라가며 부족한 설명부분을 점프 투 장고를 통해 채워보았습니다.

추후에 설명이 부족한 부분은 다시 메우도록 하겠습니다! 다음 게시물에는 part 3로 만나요! 오타와 오류 지적은 환영합니다 부족한 제 글 읽어주셔서 감사합니다 :)

' > Django' 카테고리의 다른 글

첫 번째 장고 앱 작성하기, part ① (Django 문서 참고)  (0) 2021.09.22
django 시작하기  (0) 2021.09.21