Django - 모델
● 모델
장고는 모델(Model)을 이용하여 데이터베이스를 처리한다.
보통 데이터 SQL 쿼리문을 이용해서 접근하지만,장고의 모델을 사용하면
SQL 쿼리문의 도움없이 데이터 처리가 가능하다.
- 장고 앱 migrate
python manage.py runserver 실행 시 나오는 문구를 살펴보면

적용되지 않은 migration이 있으며 관련 앱 및 적용 시 python manage.py migrate 실행해야 한다.
설치된 앱 들은 config/settings.py 파일에서 확인할 수 있다.
[파일명: projects/mysite/config/settings.py]
(... 생략 ...)
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
(... 생략 ...)
데이터베이스가 필요한 앱만 migrate가 필요하다.
config/settings.py 내에 데이터베이스에 대한 정보도 확인할 수 있다.
[파일명: projects/mysite/config/settings.py]
(... 생략 ...)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
(... 생략 ...)
** 데이터베이스 엔진은 django.db.backends.sqlite3 정의
** 데이터베이스 파일은 BASE_DIR 디렉터리 밑에 db.sqlite3 파일에 저장 // BASE_DIR은 프로젝트 디렉토리를 의미
- SQLite란?
SQLite는 주로 개발용이나 소규모 프로젝트에서 사용되는 가벼운 파일 기반의 데이터베이스이다.
개발시에는 SQLite를 사용하여 빠르게 개발하고 실제 운영시스템은 좀 더 규모있는 DB를 사용하는게 일반적이다.
명령 프롬포트애에서 데이터베이스 테이블을 생성하고자 할때 아래 명령어를 입력한다.
(mysite) C:\projects\mysite>python manage.py migrate

** migrate를 수행하면 admin, auth, contenttypes, sessions 앱들이 사용하는 테이블들이 생성된다.
- DB Browser for SQLite
SQLite의 GUI 도구인 "DB Browser for SQLite"를 설치하면 데이터베이스의 테이블들을 확인할 수 있다.
※ 설치 관련 URL
Downloads - DB Browser for SQLite
(Please consider sponsoring us on Patreon 😄) Windows Our latest release (3.12.2) for Windows: Free code signing provided by SignPath.io, certificate by SignPath Foundation. Windows PortableApp Note - If for any reason the standard Windows release does n
sqlitebrowser.org
* sqlite를 확인할 수 있는 GUI 도구
ㄴ DB Browser for SQLite - .zip (no installer) for 64-bit Windows 다운로드

** [데이터베이스 열기 -> C:\projects\mysite\db.sqlite3 파일 선택]을 통해 생성된 테이블 확인 가능
** 장고의 장점 중 하나는 테이블 작업을 위해 직접 쿼리문을 수행하지 않아도 된다.
** ORM(Object Relational Mapping)을 사용하면 쿼리문을 몰라도 데이터 작업이 가능하다.
쿼리문이란?
데이터베이스 내의 데이터를 생성, 조회, 수정, 삭제를 위한 문법
ORM(Object Relational Mappin)을 사용하면
데이터베이스의 테이블을 모델화하여 사용하기 때문에 SQL 단점이 없어진다.
※ SQL 단점
- 개발자마다 다른 쿼리문이 만들어지며, 잘못 작성된 쿼리는 시스템 성능을 저하 시킨다.
- 데이터베이스를 MySQL에서 오라클 변경 시 프로그램에 맞는 규칙으로 수정이 필요하다.
ORM은 개발자별로 독특한 쿼리문을 만들 수 없고, 쿼리문을 잘 못 작성할 가능성이 낮아진다.
데이터베이스 프로그램 종류가 변경되더라도 쿼리문이 아닌 모델을 사용하기 때문에 수정할 필요가 없다.
- 모델 작성하기
파이보는 질문과 답변을 할 수 있는 파이썬 게시판 서비스로 질문과 답변에 해당하는 데이터 모델이 필요하다.
- 모델속성
[Question 모델]
| 속성 | 설명 |
| subject | 질문의 제목 |
| content | 질문의 내용 |
| create_date | 질문을 작성한 일시 |
[Answer 모델]
| 속성 | 설명 |
| question | 질문 (어떤 질문의 답변인지 알아야하므로 질문 속성이 필요하다) |
| content | 답변의 내용 |
| create_date | 답변을 작성한 일시 |
- models.py
질문(Question)과 답변(Answer)에 해당되는 모델을 pybo/models.py 파일에 정의
[파일명: projects/mysite/pybo/models.py]
from django.db import models
class Question(models.Model):
subject = models.CharField(max_length=200) #제목 최대 200자//굴자수 길이 제한 CharField() 사용
content = models.TextField() #글자 수 제한 없음
create_date = models.DateTimeField() #시간 관련 속성
class Answer(models.Model):
# ForeignKey는 다른 모델과 연결하기 위해 사용
# on_delete=models.CASCADE의 의미는 이 답변과 연결된 질문(Question)이 삭제될 경우 답변(Answer)도 함께 삭제된다는 의미
# CASCADE 옵션은 질문을 삭제하면 그에 달린 답변들도 모두 함께 삭제
question = models.ForeignKey(Question,on_delete=models.CASCADE)
content = models.TextField()
create_date = models.DateTimeField()
** 질문 하나에 많은 답변이 등록될 수 있다. CASCADE 옵션은 질문을 삭제하면 그에 달린 답변 모두 삭제가 가능하다.
※ 장고의 속성(Field) 타입은 다양하며, 아래 URL에서 참고 할 수 있다.
https://docs.djangoproject.com/en/4.0/ref/models/fields/#field-types
Model field reference | Django documentation
The web framework for perfectionists with deadlines.
docs.djangoproject.com
- 테이블 생성하기
테이블 생성을 위해 가장 먼저 해야 할 일은 pybo 앱을
config/settings.py 파일의 INSTALLED_APPS 항목에 추가 필요
[파일명: projects/mysite/config/settings.py]
INSTALLED_APPS = [
'pybo.apps.PyboConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
INSTALLED_APPS에 추가한 pybo.apps.PyboConfig 클래스는 pybo/apps.py 파일에 있는 클래스로
pybo 앱 생성 시 자동으로 만들어지는 파일이기 때문에 따로 만들 필요가 없다.
[파일명: projects/mysite/pybo/apps.py]
from django.apps import AppConfig
class PyboConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'pybo'
특별한 경우가 아니라면 PyboConfig 클래스를 수정할 일이 없다.
- makemigrations
신규로 생성되거나 변경되면 python manage.py makemigrations 명령을 먼저 수행
이후 python manage.py migrate을 통해 명령 수행

makemigrations 명령은 모델을 생성하거나 모델에 변화가 있을 때 실행하는 명령어로
python manage.py makemigrations를 수행하면 아래 파일이 생성된다.

- sqlmigrate
makemigrations로 데이터베이스 작업 파일을 생성하고 migrate 명령을 실행하기 전에
실제 어떤 쿼리문이 실행되는지 sqlmigrate 명령으로 확인해 볼수 있다.

** python manage.py sqlmigrate pybo 0001 명령어에서
"pybo"는 앱 이름, "0001"은 생성된 작업파일 (ex : 0001_initial.py)의 일련 번호
** sqlmigrate 명령은 실행되는 쿼리만 조회할뿐 실제 쿼리가 수행되지 않는다.
- migrate
python manage.py migrate 를 통해 테이블 생성


** 실제 DB도 정상적으로 생성도니 것을 확인 할 수 있다.
** 장고에서 코딩할 때 테이블명 대신 Question과 Answer와 같은 모델을 사용한다.
● 모델 사용하기
python manage.py shell 실행
장고 셀은 필요한 환경들이 자동으로 설정되어 실행된다.

- Question 생성
>>> from pybo.models import Question, Answer
>>> from django.utils import timezone
>>> q = Question(subject='pybo가 무엇인가요?', content='pybo에 대해서 알고 싶습니다.', create_date=timezone.now())
>>> q.save()
>>> q.id
** Question 모델의 create_date 속성은 DateTimeField 탕비으로 timezone.now()로 현재 일시 대입
** 데이터가 정상 생성되면 q.id 명령어 실행 시 1이 출력되며, 생성할 때 마다 1씩 증가한다.
>>> q = Question(subject='장고 모델 질문입니다.', content='id는 자동으로 생성되나요?', create_date=timezone.now())
>>> q.save()
>>> q.id
2
** 두번째로 생성한 질문의 id는 2가 출력된다.
- Question 조회
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>, <Question: Question object (2)>]>
** 저장한 Question 모델의 데이터는 Question.objects를 통해 조회가 가능하다.
** Question.object.all()은 모든 Question 데이터를 조회하는 함수며,
<Question: Question object (1)>, <Question: Question object (2)>은 데이터의 id 값이다.
[파일명: projects/mysite/pybo/models.py]
(... 생략 ...)
class Question(models.Model):
subject = models.CharField(max_length=200)
content = models.TextField()
create_date = models.DateTimeField()
def __str__(self):
return self.subject
(... 생략 ...)
** __str__ 메소드를 추가하여 id 값 대신 제목을 표시했다.
장고 셀을 종료하기 위해소는 quit()를 입력하면 된다.
(mysite) c:\projects\mysite>python manage.py shell
>>> from pybo.models import Question, Answer
>>> Question.objects.all() <QuerySet [<Question: pybo가 무엇인가요?>, <Question: 장고 모델 질문입니다.>]> >>>
** 1과 2라는 id 값 대신 제목이 표시된다.
※ 조회하는 방법은 filter와 get 방식이 있다.
1. filter는 조건에 해당되는 데이터를 모두 리턴해주기 때문에 다건을 의미하는 QuerySet이 리턴된다.
ㄴ >>> Question.objects.filter(id=1)
ㄴ <QuerySet [<Question: pybo가 무엇인가요?>]>
2. get은 한건만 조회가 가능하기 때문에 Question 모델 객체가 리턴된다.
ㄴ >>> Question.objects.get(id=1) ㄴ <Question: pybo가 무엇인가요?>
** get은 반드시 1건의 데이터를 조회할때 사용하며, id와 같은 유일한 값으로 조회할 경우에만 사용하니 주의!
- Question 수정
>>> q = Question.objects.get(id=2)
>>> q
<Question: 장고 모델 질문입니다.>
================subject 속성 수정
>>> q.subject = 'Django Model Question'
>>> q.save() #저장 필수
>>> q
<Question: Django Model Question>
- Question 삭제
>>> q = Question.objects.get(id=1)
>>> q.delete()
(1, {'pybo.Question': 1})
** (1, {'pybo.Question': 1}) 은 Question 모델 1개가 삭제되었음을 의미
>>> Question.objects.all()
<QuerySet [<Question: Django Model Question>]>
** 전체 내용이 삭제 시 <QuerySet []> 출력
- Answer 작성
>>> q = Question.objects.get(id=2)
>>> q <Question: Django Model Question>
>>> from django.utils import timezone
>>> a = Answer(question=q, content='네 자동으로 생성됩니다.', create_date=timezone.now())
>>> a.save()
** 답변 데이터를 만들기 위해서는 질문이 필요하기 때문에 id가 2인 질문을 조회 후 question 속성에 대입
>>> a.id
1
** Answer 모델도 Question 모델과 동일하게 유일한 값을 의미하는 id가 자동 생성된다.
- Answer 조회
>>> a = Answer.objects.get(id=1)
>>> a
<Answer: Answer object (1)>
** 답변을 조회하는 방법은 질문과 동일하게 Answer의 id 값을 사용한다.
>>> a.question
<Question: Django Model Question>
** Answer 객체인 a를 사용하면 연결된 질문 확인이 가능하다.
>>> q.answer_set.all()
<QuerySet [<Answer: Answer object (1)>]>
** q.answer_set 사용 시 질문에 연결된 답변을 가져올 수 있다.
Question 모델에는 answer_set 속성이 없지만 Answer 와 Question 모델이 ForignKey로 연결되어 있기 때문에
q.answer_set 과 같은 역방향 접근이 가능하다.