Chapter 04. 모델(Model)에 관하여
앞서 언급한 것처럼 장고의 모델은 DB 테이블을 결정짓는다.
즉, 모델에는 데이터가 저장될 때 어떤 필드에 저장될 것인지, 이 데이터가 저장될 때 어떤 동작을 할 것인지 등이 포함된다.
기초
- 각 모델은 django.db.models.Model의 서브클래스다
- 모델의 각 속성(attribute)는 DB의 필드(Field)를 의미한다
- 모델을 생성하면 Django는 자동으로 생성된 DB엑세스 API(save(), delete() 등)를 제공한다
모델 생성 및 사용
# app/models.py
from django.db import models
class Person(models.Model):
class Meta:
db_table = "person"
name = models.CharField(max_length=30)
email = models.EmailField()
birth = models.DateField()
위와 같은 형태로 클래스를 정의해 모델을 정의할 수 있다
테이블의 이름을 정해주지 않으면 sqlite DB에 app_person형태로 테이블이 자동으로 만들어지지만, 메타데이터 서브클래스 Meta를 오버라이딩해서 db_table매개변수를 다시 정의해주면 person 등으로 테이블 이름으로 바꿔줄 수 있다
클래스의 각 속성은 위에 말한 것처럼 DB의 필드를 의미하는 것이며 속성 이름 = models.필드타입(옵션=옵션) 형태로 정의할 수 있다.
모델을 사용하기 위해서는 우선 장고가 우리가 만든 앱을 인식할 수 있도록 settings.py에 등록해주어야 한다.
그렇지 않으면 우리가 아무리 모델을 변경해주고 makemigrations 명령어로 migration을 만들어 주려고 해도 아래와 같이 감지하지 못한다
아래와 같이 등록하면 된다
# mysite/settings.py
INSTALLED_APPS = [
# ...
"app",
# ...
]
app은 당연히 본인이 생성한 앱 이름으로 바꿔주어야 한다
필드(Fields)
모델을 구성하는 가장 중요한 부분이자 유일한 부분이다.
장고에서 DB의 필드는 파이썬의 클래스 속성으로 정의된다.
필드의 이름을 선택할 때 clean이나 save, delete와 같이 models API에 미리 정의되어 있는 이름과 겹치지 않도록 해야한다.
필드 타입(Field Type)
- AutoField
자동으로 값이 증가하는 IntegerField.
PK값이 자동적으로 추가되므로 일반적으로 직접 사용할 일은 잘 없다
하지만 자동으로 생성되는 id라는 이름이 정 마음에 들지 않는다면 아래와 같이 변경해줄 수 있다.
# app/models.py
from django.db import models
class User(models.Model):
class Meta:
db_table = "user"
superduper_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=50)
위와 같이 AutoField(primary_key=True)로 superduper_id라는 필드를 만들어 주었다
migrate를 하고 결과물을 보면 다음과 같다
테이블의 PK필드 이름이 잘 바뀐 것을 볼 수 있다.테이블의 PK는 단 하나만 존재해야 하므로 primary_key속성을 True로 설정하지 않으면 오류가 난다
- IntegerField
정수 필드.
MinValueValidator와 MaxValueValidator를 이용해 값을 검증한다
-2147483648 ~ 2147483647까지 모든 DB에서 안전하게 사용할 수 있다
이말을 듣고 궁금해져서 테스트 해보았다
부호있는 4byte 최댓값 양수에 1을 더해줬을 때 오류없이 잘된다.
여러번 테스트를 한 끝에 결과적으로 9,223,372,036,854,775,808에서 아래와 같은 오류가 발생했다.
OverflowError: Python int too large to convert to SQLite INTEGER
즉, 'python에서는 문제없는데 SQLite에서 너무 큰 값은 처리 못해요'다
원인은 현재 사용하고 있는 SQLite의 정수가 부호있는 8byte 값이기 때문이다.
따라서 2^64bit = 18,446,744,073,709,551,616의 절반까지의 양수까지 처리할 수 있다.
SQLite가 아닌 다른 DB는 다른 정수값 체계가 있을 수 있으므로 안전하게 사용하자
추가적으로 값을 검증하는 Min/MaxValueValidator를 이용해서 다음과 같이 활용할 수 있다
# app/models.py
from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator
class User(models.Model):
class Meta:
db_table = "user"
superduper_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=50)
age = models.IntegerField(validators=[MinValueValidator(18), MaxValueValidator(250)])
만약 성인들만 이용할 수 있는 사이트를 만들고자 할 때 만18세 미만의 청소년들은 가입을 금지시킨다고 하자
그럴 때 위와 같이 django.core.validators의 Min/MaxValueValidator클래스를 이용해 값을 제한할 수 있다
결과는 다음과 같다
- FloatField
파이썬의 float자료형과 대응되는 실수 필드.
이도 역시 위의 Min/MaxValueValidator클래스를 이용해 값을 제한할 수 있다
- DecimalField(max_digits=None, decimal_places=None)
파이썬의 decimal자료형과 대응되는 실수 필드.
숫자의 최대 자릿수를 표현하는 max_digits와 소수부를 지정하는 decimal_places를 필수 인자로 가진다.
부동소수점인 Float에서 발생하는 무한소수 문제를 해결할 수 있지만 메모리를 많이 잡아먹는다
- BooleanField
True/False로 구성된 필드.
null=True 옵션을 적용하고 default옵션을 적용하지 않으면 기본값은 Null이 된다
- CharField(max_length=<int>)
문자열 필드. 최대길이를 지정하는 max_length를 필수적으로 가져야 한다
- TextField
긴 텍스트 필드. max_length가 필요없지만 만약 지정한다면 자동적으로 생성되는 form field에는 영향을 준다.
하지만 model이나 DB에는 영향을 주지 못한다.
위의 그림과 같이 max_length=20 옵션을 주면 20자 이상 텍스트를 작성할 수 없다
하지만 위와 같이 DB에 직접 수정을 하면 max_length로 제한한 길이가 무색하게 잘 수정된다.
- DateField / DateTimeField(auto_now=False, auto_now_add=False)
각각 파이썬의 datetime.date, datetime.datetime 객체로 표시되는 필드
- TimeField(auto_now=False, auto_now_add=False)
파이썬의 datetime.time객체로 표시되는 필드.
- EmailField
EmailValidator를 이용해 이메일의 유효성을 검증하는 CharField
- FileField(upload_to="", storage=None, max_length=<int>)
파일필드. PK로 지정할 수 없다
- upload_to : MEDIA_ROOT의 서브디렉토리를 결정하기 위한 옵션. settings.py에 MEDIA_ROOT='/media/'를 설정하고 upload_to="photos/%Y/%m/%d"를 설정했다면 파일은 home/media/photos/2023/04/19/file.jpg 형태로 저장된다.
- storage : 다양한 환경에 따라 서로 다른 storage를 선택해야 할 때 사용하는 옵션. 자세한 내용은 여기
- ImageField(upload_to=None, height_field=None, width_field=None, max_length=100)
업로드된 파일이 유효한 이미지인지를 검사하는 FileField
필드 옵션(Field Options)
모든 필드 타입에 사용가능한 옵션들이다
- null
기본값은 False. True라면 DB에 비어있는 값을 NULL로 저장한다.
문자열 기반 필드에서 no data(데이터가 없음)을 의미하는 값이 NULL과 빈 문자열 두가지가 혼용될 수 있으므로 CharField나 TextField에는 사용하면 안된다.
문자열 기반 필드에서 사용할 수 있는 한가지 예외는 unique=True옵션과 blank=True옵션이 함께 사용됐을 때다
이때는 빈값이 여러개 생성될 수 있으므로 unique=True옵션에 걸리지 않기 위해 null=True를 설정할 수 있다.
- blank
기본값은 False. True라면 빈 문자열을 허용한다
null이 DB에 관계된(database-related) 이슈라면 blank는 유효성 검사와 관련(validation-related)된다.
blank=False라면 이 필드는 값이 필수다.
- unique
unique=True라면 테이블 전체에서 값들이 유일한 값이어야 한다
ManyToManyField와 OneToOneField를 제외한 모든 필드 타입에서 사용할 수 있다
- default
필드의 기본값을 설정한다.
어떤 value 혹은 callable한 객체가 들어갈 수 있다.(list, set같이 mutable한 객체는 불가)
만약 callable한 객체가 들어간다면 새로운 객체가 생성될 때마다 불릴 것이다
- editable
editable=False라면 admin페이지나 ModelForm에서 보이지 않는다. 또한 모델 유효성 검사에서도 제외된다.
- db_column
필드의 이름을 별도로 설정한다. 이 옵션을 따로 사용하지 않는다면 기본적인 필드 이름이 적용된다.
- db_comment
Django 코드를 보지 않고 DB를 이용하는 사람들에게 각 칼럼의 comment를 달아줄 수 있다
- choices
각 필드 값에 사람이 읽을 수 있는 값을 별도로 설정해줄 수 있다
[(A, B), (A, B), ...]형식으로 구성되고 A는 실제 DB에 저장되는 값, B는 사람이 읽을 수 있는 값이다
관계 필드(Relationship Fields)
각 Table의 관계를 나타내는 필드
- ForeignKey(to, on_delete)
Many-to-One 관계.
현재 모델에 관련된 모델의 클래스(to)와 그 클래스의 row가 삭제됐을 때 현재 모델이 어떻게 행동할 지에 관한 on_delete옵션을 설정해주어야 한다.
모델 간의 관계를 설정할 때 상대 모델이 코드 상 뒤에 있어 NameError가 발생할 때, 문자열로 된 상대 모델의 이름으로 대체할 수 있다.(lazy relationship)
# app/models.py
from django.db import models
class Car(models.Model):
manufacturer = models.ForeignKey(
"Manufacturer",
on_delete=models.CASCADE,
)
# ...
class Manufacturer(models.Model):
# ...
pass
위와 같은 경우 테이블의 필드에는 manufacturer_id라는 _id가 붙은 이름으로 저장된다.
만약 이 이름이 싫다면 db_column옵션으로 다른 이름을 지정해주면 된다
인수(Arguments)
- on_delete : ForeignKey로 참조하는 객체가 삭제되었을 때 SQL의 행동을 결정한다(아래 옵션들은 django.db.models에 존재한다)
- CASCADE : 자신이 참조하고 있는 테이블의 데이터가 삭제되면 자동으로 자신의 데이터도 삭제
- PROTECT : ProtectedError를 발생시켜 참조된 데이터의 삭제를 방지한다
- RESTRICT : RestrictedError를 발생시켜 참조된 데이터의 삭제를 방지한다. PROTECT와의 차이는 일부 특수한 상황에서 데이터의 삭제를 허용한다
- SET_NULL : 자신이 참조하고 있는 테이블의 데이터가 삭제되면 NULL값으로 대체한다. null=True옵션일 때만 사용가능하다
- SET_DEFAULT : default값으로 대체한다. ForeignKey에 default값이 미리 설정되어 있어야 한다
- SET() : 어떤 호출된 결과로 대체한다
- DO_NOTHING : 아무것도 하지 않는다
- related_name : 참조된 객체로부터의 관계를 위한 이름. 역참조를 위한 이름이라고 생각하면 편하다.
- ManyToManyField(to)
many-to-many관계.
- OneToOneField(to, on_delete, parent_link=False)
one-to-one관계.
'프로그래밍 > Python' 카테고리의 다른 글
[Django] 장고 기초 - (5) Query Set(2) (0) | 2023.04.27 |
---|---|
[Django] 장고 기초 - (4) Query Set(1) (2) | 2023.04.22 |
[Django] 장고 기초 - (2) Template Language (0) | 2023.04.17 |
[Django] 장고 기초 - (1) 개요 및 개발 환경 구성 (0) | 2023.04.14 |
[Python] 자료형 특집 - (1) 시퀀스 타입(List/Tuple/Range) (0) | 2023.03.24 |