오늘도 개발

Django와 데이터베이스 - 1) Django 모델(Model) 본문

웹 프로그래밍/Django

Django와 데이터베이스 - 1) Django 모델(Model)

Sueeeeeee 2022. 6. 30. 10:13

models.py에서 정의한 클래스를 모델이라고 한다.

각 모델은 migration을 통해 데이터베이스에서 테이블이 된다.

 

여기서는 models.py에서 클래스 속성(=테이블의 칼럼)으로 사용할 수 있는 장고의 필드 타입을 살펴보자.

문자

CharField(max_length)

MySQL에서 varchar 타입이 됨. 글자 수 제한이 필요한 경우 사용.

 

TextField

MySQL에서 longtext타입이 됨. 글자 수 제한 없음.

class Drink(models.Model):
    korean_name = models.CharField(max_length=45) 
    english_name = models.CharField(max_length=45)
    description = models.TextField()

숫자

IntegerField

32비트 정수 저장. MySQL에서 int 타입이 됨. 

큰 정수(64비트)는 BigIntegerField, 작은 정수는 SmallIntegerField를 사용할 수 있다.

 

FloatField 

실수 저장. MySQL에서 double 타입이 됨.

 

DecimalField(max_digits, decimal_places)

실수 저장. MySQL에서 decimal(precision, scale)로 변환됨.

max_digits는 precision(전체 숫자 개수), decimal_places은 scale(소수점 이하 숫자 개수)로 매칭된다.

실수를 정확하게 표현해야 하는 경우 사용한다. (돈 등)

class Nutrition(models.Model):
   id = models.IntegerField
   one_serving_kcal = models.DecimalField(max_digits=10, decimal_places=2)

 

* FloatField VS DecimalField

둘 다 실수를 저장하고 반환하지만 숫자를 표현하는 방식이 다르다.

DecimalField를 사용하면 보여줄 숫자 개수를 정할 수 있다. (전체 숫자 개수, 소수점 이하 숫자 개수)

 

FloatField는 실수를 float 타입으로 반환하고 DecimalField는 실수를 Decimal.decimal 타입으로 반환한다.

float타입은 소수점 자리가 길어지면 반올림하기 때문에 정확도를 보장할 수 없지만 빠르게 연산할 수 있다.

decimal은 지정한 소수점까지는 항상 정확하게 보여주지만 float만큼 성능이 좋진 않다.

 

AutoField(primary_key) 

row를 추가할 때마다 자동으로 숫자를 증가시켜 붙여준다.

자동 생성되는 pk 칼럼 대신 직접 pk 칼럼을 만들고 싶을 때 사용.

primary_key=true로 설정하면 자동으로 pk 칼럼 생성하지 않고 해당 칼럼을 pk로 사용한다.

 

저장할 숫자 크기에 따라 BigAutoField 사용할 수도 있음. 

AutoField는 타입 int, BigAutoField는 타입 bigint로 생성됨.

(자동으로 생성되는 pk 칼럼은 칼럼명 id, 타입 bigint)

날짜

DateField(auto_now=False, auto_now_add=False, **options)

날짜 저장. Mysql에서 date 타입이 됨.

날짜를 직접 입력하는 경우 YYYY-MM-DD 포맷으로 넣으면 된다.

참조 테이블  

< 참고 : ForeignKey, ManyToManyField - related_name > 

< 참고 : ManyToManyField VS ForeignKey>

 

ForeignKey(ReferencingObject, on_delete=, related_name=) 

일대다 관계인 경우 설정하는 필드.

참조하는 클래스명을 인수로 넣는다.

 

- 정참조(many 테이블의 row가 one 테이블의 row를 부를 때) : 필드명 사용 

- 역참조(one 테이블의 row가 many 테이블의 row를 부를 때) : _set 매니저 사용

- related_name을 설정하면 _set 매니저 사용하지 않고 내가 정한 이름 사용

 

ManyToManyField(ReferencingObject)

다대다 관계인 경우 설정하는 필드. 

참조하는 클래스명을 인수로 넣는다.

설정 시 DB에 자동으로 연결 테이블(through table)을 생성해준다.

class Drink(models.Model):
    id = models.AutoField(primary_key=True)
    korean_name = models.CharField(max_length=45) 
    english_name = models.CharField(max_length=45)
    description = models.TextField()
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    
    # ManyToManyField는 다대다 관계의 테이블 중 하나에만 설정하면 된다
    allergy = models.ManyToManyField(Allergy, null=True)
    
class Allergy(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=45)

클래스를 두 개만 만들어도 DB에는 다음과 같이 세 개의 테이블이 생성된다.

ManyToManyField를 설정한 테이블 Drink에는 allergy 칼럼이 생성되지 않는다.

다대다 테이블의 연결 테이블에 데이터를 입력할 때는 다음과 같이 하면 된다.

# 일단 ManyToManyField에 해당하는 항목은 넣지 않고 데이터를 추가한다.
Drink.objects.create(Drink(name="coffee", category_id="1"))

# 연결 테이블에 들어갈 내용을 입력해준다.
a1 = Allergy.objects.get(id=1)
d1 = Drink.objects.get(id=1)
d1.allergy.add(a1)

데이터를 읽어올 때는 다음과 같이 실행한다.

# 1. 정참조
# ManyToManyField 필드를 작성한 클래스 A에서 다른 클래스 B의 정보를 가져올 때는 클래스명 b만 쓴다
# 1번 드링크에 포함된 모든 알레르기 유발 요인 
>>> Drink.objects.get(id=1).allergy.all()
<QuerySet [<Allergy: 대두>, <Allergy: 우유>]>

# 2. 역참조
# 클래스 B에서 A의 정보를 가져올 때는 _set 매니저를 사용한다.
# 우유가 포함된 모든 드링크 
Allergy.objects.get(name="우유").drink_set.all()

# 1번 카테고리에 있는 음료 중 알레르기 유발요인이 우유인 것
Allergy.objects.get(name="우유").drink_set.filter(category_id=1)
# 이렇게는 오류남 : Drink.objects.get(category_id=1).allergy.filter(name="우유")

필드 옵션

null = true : 데이터베이스에서 필드 값 NULL(정보 없음)을 허용함

blank = true : 템플릿에서 form의 필드 값 blank를 허용함

default : 필드의 디폴트 값 저장

unique : 해당 칼럼에 대한 Unique Index 생성

 

 

참고

Django 공식문서

Django ORM Cookbook

The right way to use a ManyToManyField in Django