db의 다대다 관계를 처음 접하고 살짝의 멘붕을 했다. 여러 테이블이 서로의 테이블의 레코드를 연결한다는 것이 이해가 되지않았다.
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가 생성되지 않습니다.
두 테이블의 데이터를 입력했다면 위와 같이 중간 테이블이 채워지게 됩니다.
직접적인 모델 간의 참조관계에 접근하는 개념이 아닌 DB와 연결되어있는 개념이라고 한다. 우선, select related / prefetch related에 대해서 알아보자.
ManyToMany관계를 넣어줄때 장점은 중간테이블을 거치지 않고 언제든지 데이터를 쉽게 추가하고 가져올 수 있다는 장점이 있다. ManyToMany 관계설정을 하지않은 경우, 중간 테이블 거쳐야 가져올 수 있다.
한 테이블에서 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개가 됩니다)
우선 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