장고는 데이터베이스를 추상화한 모델로 파이썬 클래스를 사용한다. 클래스의 멤버 변수로 테이블 스키마를 정의하고 클래스의 인스턴스인 객체를 튜플로 간주한다.
스키마를 정의하기 위해서는 앱 설계를 먼저 생각해야 한다. 예를 들어, Todo 리스트를 작성하는 사이트를 만든다고 가정해 보자. 유저를 위한 회원가입, 로그인, 로그아웃이 기본적으로 필요할 것이다. 이런 기능들은 모두 유저에 대한 정보를 기반으로 사용되기 때문에 유저의 정보를 표현하는 모델이 필요하다.
유저의 정보 중 필요한 것들은 어떤 것이 있을까? 로그인을 하기 위한 username
과 password
는 필수적으로 있어야 한다. 또한 email
을 로그인에 사용할 수도 있다. 여기에 가입한 시간도 추가해서 만들어 보자.
# user/models.py
class UserModel(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
email = models.EmailField()
date_joined = models.DateTimeField(auto_now_add=True)
일단 이 정도면 충분하다. 그 다음은 무엇이 필요할까? 유저들이 소통할 수 있도록 글을 작성하고 읽을 수 있어야 할 것이다. 수정, 삭제 기능도 필요하다.
기본적인 속성으로 제목과 내용이 있다. 거기에 작성자와 생성된 날짜, 수정된 날짜, 완료 여부 정도가 있으면 좋을 것 같다. 바로 만들어보자.
# todo/models.py
class TodoModel(models.Model):
# (Todo) N:1 (User)
author = models.ForeignKey(UserModel, on_delete=models.CASCADE, related_name="todo")
title = models.CharField(max_length=64)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
completed = models.BooleanField(default=False)
이 테이블에서 중요한 것은 author
속성이다. 이 속성이 User
와의 관계를 의미하기 때문이다. 왜 UserModel
테이블에 Todo
속성을 넣는 대신 이렇게 정의했을까?
유저와 글의 관계를 생각해보자. 한 명의 유저는 많은 글들을 작성할 수 있는 반면 글의 저자가 둘 이상일 수는 없다. 따라서 일반적으로는 Todo
쪽에 외부 키를 두는 방향으로 설계하는 것이 좋다.
이제 누군가 할 일을 작성하면 다른 유저들이 반응할 수 있게 만들어야 한다. 마음에 드는 글에 추천을 누를 수 있게 모델을 변경해보자.
유저는 여러 글에 추천을 누를 수 있고, 글이 많은 유저에게 추천을 받을 수도 있다. 이런 경우에 테이블 간의 참조를 어떻게 설정해야 할까?
생각해 보면 추천이라는 것은 독립적으로 존재할 수 없다. 유저가 글을 마음에 들어한다
라는 관계를 표현하는 개념이기 때문이다. 따라서 이 경우에는 유저와 글을 묶어서 표현하는 브릿지 테이블을 만들어서 관계를 표현하게 된다.
장고는 다대다 관계를 표현하면 자동으로 브릿지 테이블을 만들어주기 때문에 우리가 직접 만들 필요가 없다.
# todo/models.py
class TodoModel(models.Model):
# (Todo) N:1 (User)
author = models.ForeignKey(UserModel, on_delete=models.CASCADE, related_name="todo")
title = models.CharField(max_length=64)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
completed = models.BooleanField(default=False)
# (Todo) N:N (User)
likes = models.ManyToManyField(UserModel, related_name="likes_todo", blank=True)
이렇게 likes
라는 속성을 추가하면 된다. 이제 유저가 글에 추천할 수 있게 만들었다. 마지막으로 댓글을 추가할 수 있도록 댓글 모델을 만들어 보자.
하나의 글에는 많은 댓글이 달릴 수 있다. 또한 한 유저가 많은 댓글을 남기는 것도 가능하다. 다른 유저의 댓글에 추천을 할 수도 있다. 따라서 댓글에는 글, 저자가 외부 키로 존재해야 하고 내용, 생성 날짜, 추천 속성이 존재해야 한다.
# todo/models.py
class CommentModel(models.Model):
# (Comment) N:1 (User)
author = models.ForeignKey(
UserModel, on_delete=models.CASCADE, related_name="comment"
)
# (Comment) N:1 (todo)
todo = models.ForeignKey(
TodoModel, on_delete=models.CASCADE, related_name="comment"
)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
# (Comment) N:N (User)
likes = models.ManyToManyField(UserModel, related_name="likes_comment", blank=True)
이제 이렇게 정의한 모델을 기반으로 장고가 테이블을 만들어 줄 것이다.