참고 자료
https://docs.djangoproject.com/en/3.2/ref/models/fields/
장고에서 모델을 설계할 때,
i) 유일성 조건을 만족하며 (값이 겹치지 않으며)
ii) 폼에서 값을 입력하지 않아도 되는
필드를 만들고 싶은 경우가 있다. 이때는 해당 필드에 unique=True
조건과 blank=True
조건을 같이 주면 된다.
unique=True
조건은 해당 필드의 값이 겹치지 않게 하는 조건이다.
blank=True
조건은 해당 필드가 폼에서 입력될 때 빈 상태로 저장되는 것을 허용하는 조건이다.
# models.py
class User(AbstractUser):
email = models.EmailField(max_length=200, unique=True, blank=True)
그런데 unique=True
과 blank=True
조건을 동시에 쓸 때 한 가지 문제가 있다.
유저 모델의 이메일 필드에 unique=True
조건과 blank=True
조건이 있고, 회원 가입 시에 이 값을 입력받는 상황을 생각해 보자. A는 blank=True
조건이 있으므로, 이메일 필드값을 따로 입력하지 않고 회원 가입에 성공한다. 그런데 이때 이메일 필드에는 null값이 아니라 빈 문자열이 저장된다. 따라서 A가 회원 가입을 끝낸 후, B가 이메일 필드값을 입력하지 않고 회원 가입을 하려고 하면, unique=True
조건에 걸려 가입이 되지 않는다. 빈 문자열도 하나의 유일한 값으로 인식되어, 유일성 조건에 걸리기 때문이다.
그렇다면 빈 값을 입력받으면서도 unique=True
조건에 걸리지 않게 하려면 어떻게 해야 할까? null=True
조건을 주면 된다.
null=True
조건은 해당 필드의 값이 데이터베이스에 null값으로 저장되는 것을 허용하는 조건이다.여러 필드가 빈 문자열을 값으로 가지면 유일성 조건에 걸린다. 반면 여러 필드가 null값을 가질 때는 유일성 조건에 걸리지 않는다. 따라서 특정 필드에 null=True
조건을 주면,
i) 유일성 조건을 만족하며 (값이 겹치지 않으며)
ii) 폼에서 값을 입력하지 않아도 되는
필드를 만들 수 있다.
# models.py
class User(AbstractUser):
email = models.EmailField(max_length=200,
unique=True, blank=True, null=True)
문자열 기반이 아닌 필드에서는 위와 같은 방식으로 문제가 해결된다. 하지만 CharField, TextField, EmailField와 같은 문자열 기반 필드에서는 여전히 문제가 해결되지 않는다. 문자열 기반 필드는 null=True
조건이 있더라도, 폼에서 빈 값을 입력받으면 DB에도 빈 문자열로 저장된다. 따라서 null=True
조건이 없을 때와 마찬가지로 유일성 조건에 걸리게 되기 때문이다.
해결 방법은 모델 클래스 내에서 빈 값을 입력받았을 때 null값으로 바꾸어주는 함수를 정의하는 것이다.
# models.py
class User(AbstractUser):
email = models.EmailField(max_length=200,
unique=True, blank=True, null=True)
# unique=True 조건을 만족시키기 위해,
# 이메일 필드의 값이 빈 문자열인 경우 null값으로 바꾼다.
def clean(self):
if self.email == "":
self.email = None
이제 문자열 기반 필드에서도 유일성 조건을 만족하는 동시에, 값을 입력하지 않아도 되도록 설정할 수 있다.