몰입공간
[Django] related_name 속성으로 역참조 객체 불러오기(getting objects in reverse relation by setting a related_name) 본문
[Django] related_name 속성으로 역참조 객체 불러오기(getting objects in reverse relation by setting a related_name)
sahayana 2022. 1. 31. 19:21
#1. related_name
구현하려는 웹 어플리케이션이 다양한 서비스를 제공한다면, 이에 따른 데이터 관계도 분명 복잡해집니다.
이러한 참조관계에 이름을 부여하여 직관적인 이해를 돕는 장고 모델의 related_name 속성이 있습니다.
related_name은 한 모델에 같은 모델을 2개 이상 참조하는 등의 상황에 따라 필수적으로 부여해야 할 때도 있습니다.
(사실, related_name을 설정하지 않을 때 더욱 직관적인 경우도 있습니다..)
여기서는 1:N 관계의 대표격인 게시글-댓글 관계를 통해 참조와 related_name 속성을 알아보려고 합니다.
Post모델을 미리 설정했다는 가정하에 Comment모델을 생성합니다.
post 속성을 ForeignKey로 설정하고 related_name 속성에 'comments'를 설정합니다.
# models.py
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
content = models.TextField()
created_date = models.DateTimeField(auto_now_add=True)
updated_date = models.DateTimeField(auto_now=True)
#2. 정참조와 역참조
Comment 모델은 Post모델의 외래키로 받아 정참조하는 관계입니다.
따라서 Comment 모델은 post 속성으로 Post의 객체를 바로 조회할 수 있습니다.
장고 Shell을 통해 comment객체의 post 속성을 통해 post 객체의 모든 속성을 접근할 수 있습니다.
from mysite.models import Post, Comment
comment_1 = Comment.objects.get(id=5)
comment_1.post.title
>>> 'Django 블로그 튜토리얼(5) - Comment 모델 설정'
반대로 Post객체는 Comment 객체와 역참조 관계이므로 바로 접근할 수 없습니다.
post_1 = Post.objects.get(id=5)
post1.comment.all()
>>> AttributeError: 'Post' object has no attribute 'comment'
post에 달린 댓글 객체를 확인하려면 모델이름_set 으로 조회가 가능합니다.
post_1 = Post.objects.get(id=5)
post1.comment_set.all()
>>> <QuerySet[<Object Comment Object(1)>, <Object Comment Object(2)>]>
related_name은 set과 똑같은 기능을 합니다.
(템플릿 태그를 사용하는 경우에도 똑같이 작용합니다.)
post_1 = Post.objects.get(id=5)
post1.comments.all()
>>> <QuerySet[<Object Comment Object(1)>, <Object Comment Object(2)>]>
#3. 필수적인 related_name
참고로, 동일한 모델을 2개 이상의 속성으로 연결시키는 경우 related_name을 필수적으로 명시하여야 합니다.
명시하지 않을 경우 조회할 쿼리의 기준이 명확하지가 않아 마이그레이션 과정에서 오류가 나게 됩니다.
다음과 같이 댓글에 recommend 필드를 설정하고 user모델을 연결시키는 경우 필수적으로 related_name을
지정해야 합니다.
# models.py
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
content = models.TextField()
created_date = models.DateTimeField(auto_now_add=True)
updated_date = models.DateTimeField(auto_now=True)
recommend = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name = 'recommends')