Django | 스타벅스 모델(Model) 작성

Sua·2021년 1월 23일
0

Django

목록 보기
5/23
post-thumbnail
post-custom-banner

앱 생성하기

앱이란?

  • 장고 프로젝트는 여러 개의 앱으로 구성되어 있는데, 앱이란 웹사이트를 기능별로 구분해놓은 것이다.
  • 예를 들어, 홈페이지에서 상품, 결제, 채팅 등의 기능들을 앱으로 구성하는 것이다.

starbucks 프로젝트 아래에 products라는 앱을 생성한다.

cd starbucks
python manage.py startapp products

앱을 생성하면 다음과 같은 파일들이 자동으로 만들어진다.

앱 등록하기

앱을 생성하면 starbucks/settings.py에 들어가 앱 등록을 해주어야 한다. 그래야 테이블 생성이 가능하다. INSTALLED_APPS 리스트에 products를 추가한다.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'products',
]

모델 작성하기

모델이란?

  • 장고에서 모델(model)은 데이터를 관리하는 곳이다.
  • 모델은 각 앱 안의 models.py 모듈에서 정의하게 된다.
  • models.py 모듈 안에 하나 이상의 모델 클래스를 정의할 수 있으며, 하나의 모델 클래스는 데이타베이스에서 하나의 테이블에 해당된다.

스타벅스 홈페이지의 상품 모델링을 기준으로 장고 모델을 작성해보겠다.

테이블 간 관계가 눈에 잘 보이도록 간단하게 도식화해보았다.

이 관계를 바탕으로 products/models.py에서 내가 작성한 코드는 아래와 같다.

from django.db import models

class Menu(models.Model):
    name = models.CharField(max_length=50)

    class Meta:
        db_table = 'menus'

class Category(models.Model):
    name = models.CharField(max_length=50)
    menu = models.ForeignKey('Menu', on_delete=models.CASCADE)

    class Meta:
        db_table = 'categories'

class Product(models.Model):
    korean_name = models.CharField(max_length=100)
    english_name = models.CharField(max_length=100)
    description = models.CharField(max_length=300)
    is_new = models.BooleanField(default=False)
    category = models.ForeignKey('Category', on_delete=models.CASCADE)

    class Meta:
        db_table = 'products'

class Image(models.Model):
    image_url = models.URLField(max_length=2000)
    product = models.ForeignKey('Product', on_delete=models.CASCADE)

    class Meta:
        db_table = 'images'

class Allergy(models.Model):
    name = models.CharField(max_length=30)
    products = models.ManyToManyField('Product', through='AllergyProduct')

    class Meta:
        db_table = 'allergies'

class AllergyProduct(models.Model):
    allergy = models.ForeignKey('Allergy', on_delete=models.CASCADE)
    product = models.ForeignKey('Product', on_delete=models.CASCADE)
    
    class Meta:
        db_table = 'allergies_products'

class Nutrition(models.Model):
    one_serving_kcal = models.DecimalField(max_digits=5, decimal_places=1, null=True)
    sodium_mg = models.DecimalField(max_digits=5, decimal_places=1, null=True)
    saturated_fat_g = models.DecimalField(max_digits=5, decimal_places=1, null=True)
    sugars_g = models.DecimalField(max_digits=5, decimal_places=1, null=True)
    protein_g = models.DecimalField(max_digits=5, decimal_places=1, null=True)
    caffeine_mg = models.DecimalField(max_digits=5, decimal_places=1, null=True)
    size = models.CharField(max_length=30)
    product = models.OneToOneField('Product', on_delete=models.CASCADE)

    class Meta:
        db_table = 'nutritions'

모델 작성 시 체크할 것!

Field

  • CharField : 글자 수가 제한된 텍스트를 정의할 때 사용, max_length 지정
  • URLField : URL을 입력해야 할 때는 CharField 대신 사용, max_length 지정
  • DecimalField : max_digits에는 소수점 아래를 포함하여 전체 길이, decimal_places에는 소수점 아래의 길이를 지정
  • BooleanField : true/false 필드, 0 또는 1로 입력 가능

장고에서는 이것말고도 많은 속성이 존재하는데, 더 알고 싶다면 장고 속성 곰식문서를 참고하자.

자동 생성되는 id(pk)

  • 클래스에서 id를 작성하지 않았다. pk가 지정되어 있지 않으면 장고에서 알아서 id 컬럼을 만들고 pk를 생성한다.

ForeignKey의 컬럼명 작성하기

  • 장고가 아닌 직접 모델링을 했을 때는 ForeignKey의 컬럼명 뒤에 _id가 붙었으나, 장고에서는 빼고 작성한다. 장고에서 알아서 _id를 붙여 데이터베이스에 넘기기 때문이다.
# menu(O) menu_id(X)
menu = models.ForeignKey('Menu', on_delete=models.CASCADE)
  • 하지만 django shell에서 데이터 입력 시에는 menu_id=1처럼 _id를 명시해야 한다.

데이터베이스에 저장되는 테이블명 변경하기(Meta)

데이터베이스에 테이블명을 클래스명이 아닌 다른 이름으로 짓고 싶다면 Meta class를 사용한다. 아래의 예시에서 클래스명은 Menu이지만 데이터베이스에는 menus라는 테이블로 저장된다.

class Menu(models.Model):
    name = models.CharField(max_length=50)

    class Meta:
        db_table = 'menus'

CASCADE와 SET_NULL의 차이

  • ForeignKeyon_delete 속성은 참조하고 있는 테이블이 삭제가 되면 어떻게 할 것인지 결정한다.
    • CASCADE : 상위 테이블의 데이터가 삭제되면 연결되어 있던 데이터도 삭제된다.
    • SET_NULL : 외래키 지정되었던 컬럼만 null로 수정되고 나머지 데이터는 그대로 있다. null=True를 꼭 해줘야 한다.
product = models.ForeignKey('Product', on_delete=models.CASCADE)
product = models.ForeignKey('Product', on_delete=models.SET_NTLL, null=True)

관계 설정! Relationships

One-to-one relationship(1:1)

  • ProductNutrition의 관계

  • 한 쪽 테이블에 OneToOneField를 사용해 관계를 설정한다.

class Nutrition(models.Model):
    product = models.OneToOneField('Product', on_delete=models.CASCADE)

One-to-many relationship(1:N)

  • Menu(1)와 Category(N)의 관계
  • Category(1)와 Product(N)의 관계
  • Product(1)와 Image(N)의 관계
  • N인 테이블이 1인 테이블의 id를 ForeignKey로 가지면 된다.
class Category(models.Model):
    menu = models.ForeignKey('Menu', on_delete=models.CASCADE)

Many-to-many relationship(N:N)

  • AllergyProduct의 관계

1. 중간테이블이 없는 경우

  • 한 쪽 테이블에 ManyToManyField를 사용해 관계를 설정한다.
  • 컬럼명을 products처럼 자유롭게 지정할 수 있다.
  • 이렇게 하면 클래스로 중간테이블을 만들지 않더라도 데이터베이스 안에서 자동으로 다대다테이블이 생성된다.
class Allergy(models.Model):
    products = models.ManyToManyField('Product')

2. 중간테이블이 있는 경우

  • 한 쪽 테이블에 ManyToManyField를 사용하는데,through='AllergyProduct'로 중간테이블과 연결해준다.
  • 중간테이블에는 AllergyProduct 참조하는 ForeignKey를 하나씩 만들어준다.
class Allergy(models.Model):
    products = models.ManyToManyField('Product', through='AllergyProduct')

class AllergyProduct(models.Model):
    allergy = models.ForeignKey('Allergy', on_delete=models.CASCADE)
    product = models.ForeignKey('Product', on_delete=models.CASCADE)

중간테이블을 왜 만들까?

중간 테이블 클래스를 모델에 직접 정의지 않으면 두 테이블 id의 조합 외에 다른 값을 넣기가 힘들다. 따라서 중간 테이블을 만들어서 사용하는 것이 컨트롤하기 좋다.

makemigrations & migrate

여기서 잠깐! migrations가 무엇인지 알고 넘어가자.

migrations는 장고에서 모델에 대한 변경사항을 데이터베이스 스키마에 전달하는 방법이다.

migrations 관련 명령어

  • makemigrations
    • makemigrations 명령어는 모델의 변경사항을 기준으로 새로운 migration을 생성한다.
    • migration은 작업지시서라 할 수 있는데 <app-name>/migrations/0001_initial.py와 같이 파일로 저장된다.
    • makemigrations 이후에 migrations 폴더를 확인하는 습관을 갖는 게 좋다.
    • makemigrations [app-name]와 같이 앱 네임을 함께 명시해둬여 예상치 못한 migration을 방지할 수 있다.
  • migrate
    • migrate 명령어로 migrations을 적용하거나 적용 취소한다.
  • sqlmigrate
    • sqlmigrate로 실제 데이터베이스에 전달되는 SQL 쿼리문을 확인할 수 있다.
    • migrate하기 전에 확인하는 습관을 갖는 게 좋다.
  • showmigrations
    • 현재 프로젝트의 모든 migrations의 상태를 확인할 수 있다.
    • [x] : migrate 적용 후 [ ] : migrate 적용 전

정리하면,

migrations는 데이터베이스 스키마의 버전 제어 시스템이라 할 수 있다. git과 비슷하게 생각하면 된다. makemigrations는 commit과 유사하게 모델의 변경 사항을 migration 파일로 패키징하고, migrate는 이를 데이터베이스에 적용하는 일을 담당한다.

더욱 자세한 정보는 Django migrations 공식 문서를 참고하자.

모델 migration 적용하기

이제 실제로 migration 작업을 해보자!
먼저 makemigrations으로 모델 변경사항을 장고에게 알려준다.

python manage.py makemigrations products

sqlmigrate로 어떤 식으로 SQL 구문이 생성되는지 확인해주고,

python manage.py sqlmigrate products 0001

migrations 폴더 안에도 0001_initial.py 파일이 생겼다.

이제 migrate로 migration을 데이터베이스에 적용한다.

python manage.py migrate products

showmigrations로 현재 migrations가 어떤 상태인지 살펴보면

python manage.py showmigrations products

[X] 표시로 0001 initial 파일이 적용되었다는 것을 알 수 있다.

Mysql에서도 클래스와 연동된 테이블들이 생겨난 것을 확인할 수 있다. 테이블의 이름은 Meta 클래스에서 지정한 이름이다.

profile
Leave your comfort zone
post-custom-banner

0개의 댓글