장고에서 many to many field를 써야 할 때가 종종 있습니다. 예를 들자면, 게시물 하나에 태그를 구현하는 것, 친구 관계 등이 있습니다. 이 글에서는 many to many field를 다룰려는 것은 아니고, 다대다 관계에서 어떤 식으로 테이블을 생성하는지만 간단하게 알아보겠습니다.

 


 게시물 테이블이 있다고 해 보겠습니다. 보통 한 게시물의 작성자는 하나이므로, 게시물 테이블은 이런 식으로 설계해도 크게 문제는 없습니다.

 

 

 1, 2, 3은 글을 쓴 작성자의 유저 id를 의미합니다. fk로, 유저의 id를 참조합니다. board에서 user 테이블을 참조하는 외래키 정도라고 생각하시면 편하겠습니다.

 

 

 2번 유저의 이름을 GA에서 ga로 바꾸었을 때, 2번 게시물의 작성자가 ga라는 것을 알 수 있나요? 네. 알 수 있습니다. 단지, 우리는 django migrate라는 글의 작성자 id가 2였기 때문에 바뀐 이름을 참조하기 위해서 그냥 2번에 가기만 하면 됩니다.

 

 

 cho가 삭제된 경우에는 어떤가요? 게시물 입장에서는 참조하고 있는 1번인 cho가 삭제되었기 때문에, null이 되거나, 삭제가 되거나, 혹은 그 외의 방법으로 처리될 겁니다. 만약에 참조하고 있는 유저가 없다면, null 처리를 해서 삭제된 댓글이라고 해도 되고요. 즉, 유저 하나가 글을 여러 개 쓸 수 있는데, 글은 작성자가 하나이기 때문이 가능합니다.

 

 만약에, 거꾸로 유저가 게시물 id를 참조하게 되면 이상한 일이 벌어지는데요.

 

 

 만약에 3번 게시물이 삭제된다면 어떻게 될까요? cho가 쓴 글은 [1]번만 남아야 되는데, 후처리가 힘들지 않을까요? 태그 하나에 여러 개의 참조하고 있는 게시물 속성이 있습니다. 원자성이 깨져버린 것입니다. 여기서 간파할 수 있는 사실은 게시물 하나에 글쓴이가 유일하다는 것입니다. 그래서, 게시물에 대해서 글을 작성한 유저를 fk로 참조했던 것입니다.

 

 


 이제, 게시물이 여러 개의 태그를 가질 때를 생각해 봅시다. 이 때, board 테이블에 어떤 태그들을 참조하는지를 넣을 수 있습니다.

 

 

 문제는, python mktime() 글이 1, 3번 태그를 참조한다고 되어 있는데요. 원자성을 위배합니다. 반대로, 태그 테이블에 어느 게시물이 태그를 쓰는지에 대한 정보를 넣는다고 해 봅시다.

 

 

 이번에는 어떤가요? 태그도 여러 게시물에서 쓸 수 있기 때문에, 참조하는 테이블의 속성 역시 여러 개가 나오는 경우가 있습니다. 예를 들어, 게임이라는 태그를 1, 3번 게시물에서 쓴다면, game 태그는 참조하는 게시물 속성이 2개 이상이 되어 버립니다. 그러면 어떻게 해야 할까요?

 

 다행히도, (게시물 id, 태그 id) 조합은 unique 합니다. 쉽게 말해, python join()에 it, it 이렇게 2개의 중복된 태그가 들어갈 수 없다면, (게시물 id, 태그 id) 정보가 겹치지 않는다는 이야기입니다. 그러므로, 이에 대한 정보를 따로 담는 테이블을 생각해 볼 수 있습니다.

 

 그리고, 그러한 정보들을 각각 글의 id, 태그 id를 참조하게 연결하면 됩니다. 이러한 테이블을 mapping table이라고 부릅니다. 장고에서는 manytomany field로 구현할 수 있습니다. 이들이 중복해서 들어가지 않게 하려면, mapping 테이블에 (board_id, tag_id) 쌍으로 unique 조건을 걸어버리면 되겠네요.

 

 


 조금 더 어려운 예시 하나. 팔로우와 팔로워는 어떻게 구현하면 좋을까요? 일단, 팔로우나 팔로워는 유저간에 이루어지는 무언가입니다. 따라서, mapping table에는 user에 대한 참조 정보가 들어갈 겁니다.

 

 

 여기까지는 별로 어렵지 않습니다. 문제는, 방향이 있다는 것입니다. 방향이 있다는 말은 1이 3을 팔로우 하는 것이랑, 3이 1을 팔로우 하는 것이랑 별개라는 의미입니다. 1이 3을 팔로우 한다면, 아래와 같은 데이터가 mapping table에 들어가면 됩니다.

 

 

 from을 팔로우를 하는 사람, to는 팔로우를 당하는 사람을 의미합니다. from이 1이고, to가 3이라는 의미는 1이 3을 팔로우 한다는 의미입니다. 3이 1을 팔로우하는 데이터가 mapping table에 추가로 들어간다면 어떻게 될까요?

 

 

 from은 3, to는 1이다. 라는 데이터를 추가하면 됩니다. 물론, from과 to는 user를 참조하는 fk가 되겠네요.