정참조 / 역참조

HS L·2023년 4월 20일
0

내일배움캠프

목록 보기
33/73
post-custom-banner

Django

정참조 역참조

'참조하는 객체(ForeignKey를 가진 객체)'가 '참조되어지는 객체(ForeignKey와 관련된 객체)'를 참조하는 것을 정참조 라고 한다.
이것과 반대가 되는 '참조되어지는 객체(ForeignKey와 관련된 객체)'에서 '참조하는 객체(ForeignKey를 가진 객체)'를 참조하는 것을 역참조 라고 한다.

모델 예시

class Post(models.Model):
    class Meta:
        db_table = "post"

    title = models.CharField("title", max_length=50)
    author = models.ForeignKey(UserModel, on_delete=models.CASCADE)
    content = models.CharField("content", max_length=225)
    ...


class PostComment(models.Model):
    class Meta:
        db_table = "post_comment"

    post = models.ForeignKey(Post, on_delete=models.CASCADE,
    		related_name='comments')
    author = models.ForeignKey(UserModel, on_delete=models.CASCADE)
    content = models.CharField("content", max_length=225)
	...

위의 두 모델 중에서 PostComment는 Post의 key를 ForeignKey로 가지고 있다.

  • ForeignKey를 지정하는 부분에서 역참조 할때의 편의성을 위해 related_name을 지정해줬다. related_name이 없더라도 _set을 사용하여 역참조가 가능하다.

정참조

예시

PostComment에서 → 관련된 Post를 참조

# PostComment의 id가 <num>인 객체 a를 불러옴
a = PostComment.objects.get(id=<num>)

# 불러온 a에서 ForeignKey를 사용하여 관련된 Post객체 b를 가져온다
b = a.post
=> 같은 의미 b = PostComment.objects.get(id=<num>).post

이때 a가 'Post객체 중 id가 1인 객체'와 관련된 경우 b의 값은 Post object (1)이다.

이렇게 'ForeignKey를 사용하여 참조하는 객체'에서 '참조되어지는 객체'를 참조하는 과정이 정참조에 해당한다.

역참조

정참조에서 ForeignKey처럼 참조하기 위한 속성이 있듯이 역참조에서도 '정참조할때의 ForeignKey의 역할'에 대응하는 속성이 있어야 한다.

related_name이 없더라도 역참조가 가능하다고 언급했었는데 자세히 말하자면 '참조하고자 하는 Model'에서 ForeignKey를 지정할때, '참조되어질 Model'의 속성에 ForeignKey에 대응하는 '_set' 속성을 만들어 준다.

related_name은 이 '_set' 속성을 사용하기 편하도록 특정 명칭으로 정해주는 것이다.

다르게 표현해보자면
'ForeignKey의 원래 주인(Post)'이 'ForeignKey를 가진 모델(PostComment)'을 참조하기 위한 속성값 이라고 볼 수 있다.
_set과 관련해서는 아래 역참조 예시에서 한번 더 다뤄보자.

예시

Post에서 → 관련된 PostComment를 참조

# Post의 id가 <num>인 객체 c를 불러옴
c = Post.objects.get(id=<num>)

# 불러온 c에서 PostComment를 역참조하여 관련된 객체 d를 가져온다
d = c.comments.all()
=> 같은 의미 d = Post.objects.get(id=<num>).comments.all()

c.comments.all()에서 comments는 PostComment의 ForeignKey에 지정해준 related_name이다.
한개의 게시글(Post)에 여러개의 댓글(PostComment)이 있을 수 있기때문에 만약 c가 id=1인 Post라고 한다면 d는 1번 Post의 댓글 객체 전체가 된다.

이렇게 '참조되어지는 객체'에서 'ForeignKey를 사용하여 참조하는 객체'를 참조하는 과정이 역참조에 해당한다.

PostComment의 ForeignKey의 related_name 속성 지정이 없는 경우.

# Post의 id가 <num>인 객체 c를 불러옴
c = Post.objects.get(id=<num>)

# 불러온 c에서 PostComment를 역참조하여 관련된 객체 d를 가져온다
d = c.postcomment_set.all()
=> 같은 의미 d = Post.objects.get(id=<num>).postcomment_set.all()

결과값은 동일하게 나온다.
related_name사용예시에서 comments의 실제 의미가 postcomment_set을 쉽게 사용할 수 있도록 네이밍을 해준 것이라는 것을 알 수 있다.

_set 사용 변수명?

여기서 한가지 의문이 생길 수 있다. 다른 변수들은 한번 선언을 했기때문에 이해한다 치고, ForeignKey에 대응하는 '_set'을 사용한다는 것 까지는 알겠는데 '_set'에 붙는 postcomment는 갑자기 어디서 나온건가 하는 의문이다.
문법상으로 postcomment자체에 큰 의미는 없다.. 무슨말이냐면 postcomment자리가 역참조할 변수명을 선언해주는 자리로 postcomment 대신에 다른 어떤 단어가 들어가도 결과값이 달라지지는 않는다. galaxy_set을 사용할 수도 있고 apple_set을 사용할 수도 있다.
다만 편의상 관례적으로 Django에서 '<역참조할 모델의 소문자명>_set'으로 만들어 주고 있기 때문에 postcomment가 의미를 가지게 된 것이고, postcomment_set으로 사용하는 것이다.

정리하자면 역참조하기 위해 '_set'을 생성하는 과정에서는 문법상 어떤 단어를 사용해도 상관이 없지만 ForeignKey로 참조되어지는 경우 Django에서 '_set'을 '<역참조할 모델의 소문자명>_set'으로 만들어 준다. 따라서 이미 postcomment_set으로 생성이 됐기 때문에 실제실행과정에서는 postcomment가 아닌 다른 단어를 쓰게되면 실행이 되지 않게 된다.

참고 링크

profile
식이
post-custom-banner

0개의 댓글