ManyToManyField

이지훈·2021년 6월 23일
0

TIL

목록 보기
28/33
post-thumbnail

1. Many To Many relationship

db의 다대다 관계를 처음 접하고 살짝의 멘붕을 했다. 여러 테이블이 서로의 테이블의 레코드를 연결한다는 것이 이해가 되지않았다.

2. 작성법

application의 models.py에서 작성한다.

class Actor(models.Model):
    first_name = models.CharField(max_length=45)
    last_name = models.CharField(max_length=45)
    date_of_birth = models.DateField()

    class Meta:
        db_table = "actors"
        
class Movie(models.Model):
    title = models.CharField(max_length=45)
    release_date    = models.DateField()
    running_time    = models.IntegerField()
    actors          = models.ManyToManyField(Actor, related_name='movies')

    class Meta:
        db_table = "movies"

다음과 같이 ManyTOMany field를 작성하면 Django에서는 두 테이블을 연결하는 중간 테이블을 생성한다.

저의 경우에는 맨 밑의 movies_actors라는 db가 중간테이블로 생성되었습니다.

이 중간 테이블은 두 테이블을 참조해서 id를 가지게 되므로 두 테이블의 데이터가 없다면 중간 테이블의 primary key가 생성되지 않습니다.

두 테이블의 데이터를 입력했다면 위와 같이 중간 테이블이 채워지게 됩니다.

3. 정참조와 역참조를 사용하는 이유

직접적인 모델 간의 참조관계에 접근하는 개념이 아닌 DB와 연결되어있는 개념이라고 한다. 우선, select related / prefetch related에 대해서 알아보자.

  • SQL 문법 중 Join을 실시하는 Django의 ORM이다.
  • 일반적인 Many to One 또는 One to One 관계의 외래키 컬럼을 사용해서 참조관계에 있는 테이블을 지정한다.
  • 정참조 관계에 있는 테이블에 사용한다.
  • 사용하면 Join을 완료한 데이터를 DB로 부터 가져온다.
    하나의 쿼리로 진행된다.
  • Select Related와 비슷하게 Join을 수행하는 ORM
  • Many to Many 또는 Many to One 관계에서 역참조를 진행할 때 사용한다.
  • 사용하면 하나의 쿼리가 아닌 별도의 쿼리들이 수행되며 해당 쿼리의 결과를 파이썬에서 Join한다.

4. ManyToManyField을 사용할 때의 이점

ManyToMany관계를 넣어줄때 장점은 중간테이블을 거치지 않고 언제든지 데이터를 쉽게 추가하고 가져올 수 있다는 장점이 있다. ManyToMany 관계설정을 하지않은 경우, 중간 테이블 거쳐야 가져올 수 있다.

5. _set 말고 Related name를 써야할 때

한 테이블에서 2개 이상의 attribute를 참조할 때 사용됩니다.

한 고등학생이 진학사라는 대학 지원 사이트에 1지망, 2지망을 기재한다고 가정합시다.

class Student(models.Model):
    name       = models.CharField(max_length = 25)
    choice     = models.ForeignKey('Occupation', on_delete = models.CASCADE)
    choice_2nd = models.ForeignKey('Occupation', on_delete = models.CASCADE, null = True, related_name = 'appliers')
    
class University(models.Model):
    name       = models.CharField(max_length = 50, related_name = 'second_appliers')

Student 객체에서 University 객체를 참조하는데, Student 테이블의 1지망과 2지망을 동시에 참조하기 때문에 University에서 역참조할 때, 어떤 컬럼의 지망인지 모르게 됩니다.

*Studnet 테이블1지망2지망
학생1서울대고려대
학생2고려대경희대

다음과 같이 지원했다고 가정할 때, 객체의 인스턴스를 1지망으로 선택한 지원자와 2지망으로 선택한 지원자가 따로 구별되지게 됩니다.

이렇게 컬럼별에 따라서 참조를 하는데 한 테이블에 2개 이상의 참조를 할 필요가 있을 때, related_name을 사용해서 가져올 수 있습니다.

사실 이것은 다대다 보다는 1대다 모델로 만들어지고, 다대다로 만들어졌을 때는 중간 테이블이 참조하는 테이블만큼 생성됩니다. (5지망 까지 있다면 중간 생성 테이블이 5개가 됩니다)

6. QuerySet

우선 queryset을 사용하기 위해서는 manager를 알아야합니다.
우리는 User 모델이 가지고 있는 메서드인 objects를 사용해서 레코드를 가져옵니다.

User.objects
<django.contrib.auth.models.UserManager object at 0x00000189A4B75688>

manager란 쿼리셋을 불러올 때 사용하는 것입니다.
우리는 여기서 all(), count() 같은 API를 사용하게 됩니다.

objects.all() : 모든 쿼리셋 반환
objects.count() : 객체의 개수 반환
objects.first() : 첫 번째 객체 반환
objects.last() : 마지막 객체 반환
objects.annotate() : 개체와 관련한 집계함수를 사용하는 객체 반환
objects.exclude() : 지정한 매개변수를 포함하지 않는 새 객체 반환
objects.include() : 지정한 매개변수를 포함하는 새 객체 반환
objects.filter() : 조회한 매개변수와 일치하는 새 객체를 반환
등등이 있습니다.


참고
https://king-minwook.tistory.com/67
https://codermun-log.tistory.com/179
https://velog.io/@brighten_the_way/Django%EC%99%80-Reverse-relations%EA%B3%BC-Relatedname
https://docs.djangoproject.com/en/2.2/ref/models/querysets/#queryset-api

profile
꾸준하게 🐌

0개의 댓글