구현하고자 하는 테이블의 형태는 같지만, 필자는 데이터 변수와 타입 등을 다르게 예시로 했다.
모델 필드에 ForeignKey를 사용한다면 두 테이블을 이어주기 위해 중간테이블 모델을 추가해줘야 한다.
일단 두 테이블을 연결하기 위해서는 class에 중간테이블 모델을 선언해야 된다.
class Actor(models.Model):
name = models.CharField()
age = models.IntegerField()
class Movie(models.Model):
title = models.CharField()
score = models.IntegerField()
class MovieActor(models.Model): # 중간 테이블
actor = models.ForeignKey('Actor', on_delete=models.CASCADE)
movie = models.ForeignKey('Movie', on_delete=models.CASCADE)
In [1]: a1 = Actor.objects.create(name='Bob', age=12)
In [2]: m1 = Movie.objects.create(title='Armageddon',score='5')
In [3]: MovieActor.objects.create(actor=a1, movie=m1)
In [1]: a1 = Actor.objects.get(id=1)
#중간테이블 이름 together라고 가정.
#_set은 역참조를 의미
In [2]: a1.together_set.all()
Out[3]: <QuerySet [<MovieActor: MovieActor object (1), <MovieActor: MovieActor object (2)>]
In [4]: a1.together_set.get(id=1).movie
Out[5]: <Movie: Movie object (1)>
In [6]: a1.together_set.get(id=1).movie.name
Out[7]: 'Armageddon'
이 필드를 사용하면 두 테이블을 이어주는 중간테이블을 선언하지 않아도 된다.
class Actor(models.Model):
name = models.CharField()
age = models.IntegerField()
class Movie(models.Model):
title = models.CharField()
score = models.IntegerField()
actors = models.ManyToManyField(Actor, related_name='movies')
In [1]: a1 = Actor.objects.create(name='Bob', age=12)
In [2]: m1 = Movie.objects.create(title='Armageddon',score='5')
In [3]: m1.actors.add(a1) #Movie 아마게돈에 Actor 밥을 넣어주었다.
In [4]: m1.save() ###### 잊지말고 하자.. 안그럼 저장이 안됨.
In [1]: m1 = Movie.objects.get(id=1)
In [2]: m1.actors.get() #하나의 actor를 참조했을 경우 가능. 만약 둘 이상이면 get()안에 특정 actor의 id값을 넣어줘야 한다.
Out[3]: <Actor: Actor object (1)>
-------또는-------
In [2]: m1.actors.all() #이렇게하면 m1에 해당하는 actor들을 불러온다.
Out[3]: <QuerySet [<Actor: Actor object (1)>, <Actor: Actor object (2)>]>
In [4]: m1.actors.get().name #값이 하나일 경우.
Out[5]: 'Bob'
-------또는--------
In [4]: m1.actors.get(id=1).name #2개 이상일시 지정함. or m1.actors.get(name='Bob')
Out[5]: 'Bob' or <Actor: Actor object (1)>
Actor가 Movie의 title을 정참조하려고 한다.
class ActorView(View):
def get(self, request):
actors = Actor.objects.all()
result = []
for actor in actors:
movies = actor.movies.all() #이 부분.
movies_list = []
for movie in movies:
movies_info = {
'title' : movie.title
}
movies_list.append(movies_info)
actor_info = {
'name' : actor.name
'age' : actor.age
'movies' : movies_list
}
result.append(actor_info)
return JsonResponse({'result'}, result}, status=200)
movies = actor.actor_set.all()
되야 한다. actor변수를 actor(클래스지만 앞에 소문자로 씀)를 역참조하겠다는 의미.actors = movie.actors.all()
로 불러오면 된다.ForeignKeyField를 사용할 경우, 중간테이블을 만들어야되는 번거로움이 조금 있다.
python shell에서 데이터를 CRUD할 때, 중간테이블을 거쳐서 해당 테이블로 가야 된다.
ManyToManyKey로 정/역참조할 경우, 중간테이블이 자동으로 생성된다.
중간테이블을 CRUD할 수는 없지만, 참조한 테이블의 값을 부를 때 중간테이블을 거치지 않아서 shell에서 데이터를 상대적 쉽게 추가 및 삭제할 수 있다.