본문 바로가기
  • 실행력이 모든걸 결정한다
Django

[Django] Database 사용

by 김코더 김주역 2021. 8. 6.
반응형

1. DB 엔진 설정

DB 설정은 /mysite/settings.py에서 할 수 있다.

 

튜토리얼 문서(https://docs.djangoproject.com/ko/3.2/intro/tutorial02/)에 의하면, /mysite/settings.py에서는 기본적으로  sqlite3 DB를 사용하도록 셋팅되어있으며, 그 외의 엔진을 사용할 경우에는 추가적인 연결 파라미터가 필요하다고 명시되어있다.

 

 

 

2. DB 파라미터 (sqlite3가 아닌 엔진을 사용할 경우)

DATABASES = {
    'default': {
        'ENGINE':[DB 엔진],
        'NAME':[DB 이름],
        'USER':[DB ID],
        'PASSWORD':[DB PASSWORD],
        'HOST':[DB 주소],
        'PORT':[포트 넘버]
    }
}

 

▣ ENGINE

sqlite3 : django.db.backends.sqlite3

postgresql : django.db.backends.postgresql

mysql : django.db.backends.mysql

oracle : django.db.backends.oracle

 

 

 

3. models.py

- DB 테이블을 구현한 클래스들을 모아두는 곳이다.

 

1) 테이블과 속성

 

장고의 ORM은 테이블의 구조를 클래스로 표현한다. 테이블 모델들은 models.Model 클래스를 상속 받아야 하는데, 정의한 필드 외에도 Model 클래스가 제공하는 여러 오브젝트와 메소드들을 이용할 수 있다.

튜토리얼 문서에 있는 샘플 코드다.

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):
    # ForeignKey 필드를 사용할 때는 on_delete 옵션을 필수로 지정해야 한다.
    question = models.ForeignKey(Question, on_delete=models.CASCADE) # 참조 필드가 삭제될 경우 같이 삭제
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

 

그리고, 위 내용을 DB 테이블 구조로 변환하면 다음과 같을 것이다.

<구조>

Table : Question

-> Field : id, type : integer (기본키는 장고에서 id 컬럼으로 자동 생성됨)

-> Field : question_text, type : varchar(200)

-> Field : pub_date : type : datetime

Table : Choice

-> Field : id, type : integer (기본키는 장고에서 id 컬럼으로 자동 생성됨)

-> Field : question_id (FK로 지정된 컬럼은 _id 접미사가 붙음), type : integer

-> Field : choice_text, type : varchar(200)

-> Field : votes, type : integer

 

그 외의 Field 타입 및 속성은 아래에 링크한 문서에서 확인하면 된다.

https://docs.djangoproject.com/en/4.1/ref/models/fields/

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 

또한, Field 타입 클래스를 상속받아 커스텀 필드를 만들 수 있다는 사실도 알아두자.

https://docs.djangoproject.com/en/4.1/howto/custom-model-fields/

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 

 

2) 모델 메소드

- 테이블을 클래스로 처리하는 ORM 기법의 특징에 따라 모델 클래스에는 메소드도 가질 수 있다.

- 모델 클래스에 정의하는 메소드는 항상 self 인자를 가지며, 레코드 단위에만 영향을 미치게 된다.

- 예를 들어, 다음과 같은 메소드들이 대표적으로 많이 사용된다.

def __str__(self): # 객체를 읽을 수 있는 문자열로 표현
    return self.name
    
def get_absolute_url(self): # 자신 객체를 지칭하는 URL로, 주로 Admin이나 템플릿에서 활용됨
    return reverse('snack:snack_detail', args=(self.id,))

 

 

3) 모델 매니저

- 테이블의 모든 레코드 수를 카운트하는 등 테이블 레벨의 동작을 정의할 때 사용되는 속성으로, models.Manager 타입으로 정의된다.

- Manager 클래스를 통해 DB 쿼리가 이루어지며, 테이블 레벨에서의 동작은 Manager 클래스의 메소드를 통해 이루어진다.

- Manager 속성의 디폴트 이름은 objects로, objects의 디폴트 매니저는 models.Manager()이다. 또, Manager 속성은 모델 클래스를 통해서만 접근할 수 있고 모델 객체를 통해서 접근할 수 없다.

Snack.objects.all()

- 커스텀 모델 매니저는 model.Manager 클래스를 상속받아서 사용하면 된다. objects가 아닌 다른 이름의 속성으로 생성해도 되는데, 이 경우에는 2개의 Manager가 존재하는 것이다.

- 모델 매니저의 다양한 활용 방법이 알고싶다면 아래 공식 문서를 참고하자.

https://docs.djangoproject.com/en/4.1/topics/db/managers/

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 

 

4) Meta 내부 클래스 속성

- Meta 내부 클래스에 모델에 대한 메타데이터를 정의할 수 있다.

class Snack(models.Model):
    ...

    class Meta:
        verbose_name='snack'
        verbose_name_plural='snacks'
        db_table='snack_snacks'
        ordering=('-create_dt',)

자주 사용되는 메타 항목들은 다음과 같다.

  • verbose_name : 모델 객체의 별칭
  • verbose_name_plural : verbose_name에 대한 복수 명칭
  • db_table : DB에 저장되는 테이블 이름을 저장한다. 디폴트는 "앱명_클래스명"이다.
  • ordering : DB에서 가져온 모델 객체 리스트에 대한 정렬 기준 필드들이다. 디폴트는 오름차순이며, 위의 예제와 같이 '-' 접두사를 앞에 붙이면 내림차순이 된다. DB에 저장하는 순서를 의미하는 것이 아님에 유의하자.

 

그 외의 메타 항목들은 아래 공식 문서에서 확인하길 바란다.

https://docs.djangoproject.com/en/4.1/ref/models/options/

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 

 

5) 모델 간 관계

- 장고에서는 한쪽 방향으로 관계를 생성하거나 변경할 때, 반대 방향으로의 관계를 자동으로 연결해주는 관계 매니저를 제공한다. 그래서 역방향으로도 필터 메소드(filter())로 검색이 가능하다는 편리함이 생긴다. 우리는 이러한 동작을 잘 이해하고 알맞게 모델의 필드를 정의할 필요가 있다.

- 연관 관계를 맺고 있는 모델 객체는 주로 QuerySet API로 다루기 때문에, 아래에 링크한 QuerySet API에 관한 공식 문서를 읽어보면 도움이 많이 될 것이다.

https://docs.djangoproject.com/en/4.1/ref/models/querysets/#queryset-api

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 

(1) N:1

- 모델의 필드를 정의할 때 ForeignKey 필드를 사용한다.

- N:1 관계에서, 1쪽 객체에서는 [N쪽 모델 클래스의 소문자명]_set 속성을 사용함으로써, 그리고 N쪽 객체에서는 ForeignKey 필드 속성을 그대로 사용함으로써 서로 참조가 가능하다. 예를 들어, Question-Choice의 경우에는 N쪽인 Choice 객체는 question 속성을, 1쪽인 Question 객체는 choice_set 속성을 사용하여 양방향간에 참조가 가능한 것이다.

[Choice 객체].question
[Question 객체].choice_set.all()

- 아래 공식 문서에서 N:1 관계에서의 다양한 API 사용 예시를 볼 수 있다.

https://docs.djangoproject.com/en/4.1/topics/db/examples/many_to_one/

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 

(2) N:N

- 모델의 필드를 정의할 때 ManyToManyField 필드를 사용한다. N:N 관계를 맺는 두 모델 중 한쪽에만 정의하면 된다.

- ManyToManyField 필드가 없는 쪽에서는 [상대 N쪽 모델 클래스의 소문자명]_set 속성을 사용함으로써, 그리고 ManyToManyField 필드를 정의한 쪽에서는 ManyToManyField 필드 속성을 그대로 사용함으로써 서로 참조가 가능하다.

- 아래 공식 문서에서 N:N 관계에서의 다양한 API 사용 예시를 볼 수 있다.

https://docs.djangoproject.com/en/4.1/topics/db/examples/many_to_many/

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 

(3) 1:1

- 모델의 필드를 정의할 때 OneToOneField 필드를 사용한다. 1:1 관계를 맺는 두 모델 중 한쪽에만 정의하면 된다

- 양방향 모두 하나의 객체만 반환한다.

- OneToOneField 필드가 없는 쪽에서는 [상대 1쪽 모델 클래스의 소문자명] 속성을 사용함으로써, 그리고 OneToOneField필드를 정의한 쪽에서는 OneToOneField 필드 속성을 그대로 사용함으로써 서로 참조가 가능하다.

- 대입할 때는 add() 같은 QuerySet API를 사용할 필요 없이 바로 '='로 대입하면 된다. 1:1 연결이 풀린 객체에는 예전 내용이 남아 있다는 점에 유의하길 바란다.

- 아래 공식 문서에서 1:1 관계에서의 다양한 API 사용 예시를 볼 수 있다.

https://docs.djangoproject.com/en/4.1/topics/db/examples/one_to_one/

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 

(4) 역방향으로 필터 메소드 사용

- 외래키가 없는 모델에서 외래키가 있는 모델으로 즉, 역방향으로 필터 메소드(filter())를 사용하려면, 모델 클래스의 소문자 이름을 속성명으로 사용한다. 아래 예시에서는 Choice 클래스를 choice로 표기하였다.

Question.objects.filter(choice__votes__gt=10)

아래 코드는 아까 전에 살펴보았으나, 여러분들의 편의를 위해 한 번 더 첨부한다.

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)

 

(5) 관계 매니저

- 모델 매니저 중에서 모델 간 관계에 대한 기능 및 DB 쿼리를 담당하는 클래스를 말한다.

- 한쪽 방향으로 관계를 생성하거나 변경할 때, 반대 방향으로의 관계를 자동으로 연결해주는 객체다.

- 관계 매니저는 객체들의 집합을 다루기 위한 클래스이기 때문에 N:1, N:N 관계에서만 사용된다. 앞서 설명했던 [N쪽 모델 클래스의 소문자명]_set 속성이 관계 매니저 클래스의 객체인 것이다. 그리고, N:N 관계에서는 ManyToManyField 타입의 필드가 관계 매니저 객체이기도 하다.

- 관계 매니저 객체라는 것은 관계 매니저 클래스에서 제공하는 메소드를 사용할 수 있다는 의미다. 아래 예시에서는 create() 메소드를 사용했다.

q=Question.objects.get(pk=1)
q.choice_set.create(choice_text='Apple', votes=0)

관계 매니저 클래스에서 제공하는 메소드는 다음과 같은 것들이 있다.

  • add(*objs, bulk=True) : 인자로 주어진 모델 객체들을 관계 매니저가 관리하는 집합에 추가한다.
  • create(**kwargs) : 새로운 객체를 생성해서 이를 DB에 저장하고 관계 매니저가 관리하는 집합에 추가한다. 그리고 새로 생성된 객체를 반환한다.
  • remove(*objs, bulk=True) : 인자로 주어진 모델 객체들을 관계 매니저가 관리하는 집합에서 제거한다.
  • clear(bulk=True) : 관계 매니저가 관리하는 집합에 있는 모든 객체를 삭제한다.
  • set(objs, bulk=True, clear=False) : 관계 매니저가 관리하는 집합의 내용을 변경한다. clear=True면 clear() 메소드를 통해 기존 항목을 모두 지운 뒤에 objs 내용을 새로 한꺼번에 추가하는 반면에, clear=False면 기존 항목에서 add() 메소드로 항목을 추가하거나 remove() 메소드로 항목을 지운다.

※ bulk는 여러 건의 데이터를 한 번에 수정하는 벌크 연산 수행 여부를 뜻한다.

※ 바로 위에 언급한 메소드들은 실행 즉시 DB에 반영되기 때문에, save() 메소드를 호출할 필요가 없다.

※ remove(), clear() 메소드는 외래키 관계에서 null이 True로 허용되어 있어야 사용할 수 있으며, 관계가 맺어진 상대 객체를 삭제하는 것이 아니고 딱 관계만 끊는 것이다.

 

 

+ 추가) 외부 DB의 테이블을 모델 클래스로 적용하기

/mysite/settings.py의 DATABASES에 설정한 외부의 DB를 불러오는 경우에는 "python manage.py inspectdb" 명령어를 통하여, DB의 테이블들이 각각 모델 클래스로 변환된 결과를 콘솔창에 출력시키면 된다. 그리고 이 결과를 앱 내의  models.py에 붙여넣으면 된다.

* Mysql : 5.7이상의 버전 지원

 

 

 

4. models 활성화

</users/apps.py>

users.apps.UsersConfig가 위치한 곳이다.

from django.apps import AppConfig


class UsersConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'users'

 

models.py에서 작성한 클래스들을 /mysite/setting.py의 INSTALLED_APPS[] 리스트에서 활성화시켜야 한다.

필자는 users앱 내에서 작성했으므로 'users.apps.UsersConfig'를 추가했다.

INSTALLED_APPS = [
    'users.apps.UsersConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

 

 

 

5. 변경사항 적용

두 명령을 차례대로 사용하여 변경사항을 데이터베이스에 적용할 수 있다.

 

1) makemigrations

python manage.py makemigrations

설명 : 새로운 모델을 만들었거나 모델을 변경시킨 사실을 migration으로 저장시키고 싶다는 것을 Django에게 알리는 명령어

 

 

2) migrate

python manage.py migrate

설명 : makemigrations 명령에 의해 생긴 마이그레이션 파일들을 이용하여 모델에서의 변경사항들과 데이터베이스 스키마 간의 동기화를 수행해 주는 명령어

※ "python manage.py sqlmigrate [애플리케이션명] [마이그레이션 파일 버전]" 명령어를 입력하면 장고가 migrate 수행 시 사용했던 SQL 문을 조회할 수 있다.

python manage.py sqlmigrate users 0001

※ "python manage.py showmigrations 명령어를 입력하면 모든 마이그레이션을 보여주고, 각 마이그레이션별 적용 여부를 알 수 있다.

 

 

 

6. DB 사용

이제 객체 스타일로 DB를 사용할 수 있게 되었다.

튜토리얼 공식 문서에 나와 있는 사용 예제를 보자.

https://docs.djangoproject.com/en/3.2/intro/tutorial02/#playing-with-the-api

 

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

 

사용 예제를 보면, DB 레코드를 객체 형태로 다루고 있는 모습이다.

model 객체에 대해 save() 메소드를 적용해주면 레코드를 저장할 수 있고,

model 클래스에 대해 objects.all() 메소드를 사용하여 모든 레코드를 조회할 수도 있다.

 

또한, model 클래스 내에 커스텀 메소드를 적용할 수도 있다. 아래 예시에 있는 __str__() 메소드는 객체를 문자열로 표현할 때 사용하는 함수로, Admin 사이트나 쉘 등에서 테이블(객체)을 표현할 때 쓰인다.

 

반응형

댓글