역참조 물론 한번 작성했지만 자시 정리하자!
역참조를 사용할때는 one-to-one 필드가 아닌 경우는 데이터를 set으로 받아 주어야 한다.
one-to-many, many-to-many 같은 경우는 여러 유저의 정보를 가져오므로 생각해보면 당연한것도 같다.
- 역참조할 대상을 정할때는 테이블 뒤에 _set을 붙여준다.
- _set을 해서 데이터를 가져오는 경우 데이터는 쿼리셋 형태로 가져오게 된다.
- _set.filter() 를 사용해서 원하는 데이터만 가져올 수도 있다.
- related_name 역참조 별칭을 내가 원하는데로 정할 수 있다.
- 기본 역참조 예시 코드
# 역참조를 해서 해당 user의 UserProfile.hoby를 가져오는 경우로 예시를 들겠다.
# 역참조 안한 경우
user_profile = UserProfile.objects.get(user=user)
hobbys = user_profile.hobby.all()
# 역참조를 하는 경우
hobbys = user.profile_set.hobby.all()
- 역참조 활용
역참조를 활용해 나와 같은 취미를 가진 사람을 찾는 코드
def get(self, request):
user = request.user
hobbys = user.userprofile.hobby.all()
for hobby in hobbys:
# exclde : 매칭 된 쿼리만 제외, filter와 반대
# annotate : 필드 이름을 변경해주기 위해 사용, 이외에도 원하는 필드를 추가하는 등 다양하게 활용 가능
# values / values_list : 지정한 필드만 리턴 할 수 있음. values는 dict로 return, values_list는 tuple로 ruturn
# F() : 객체에 해당되는 쿼리를 생성함
hobby_members = hobby.userprofile_set.exclude(user=user).annotate(username=F('user__username')).values_list('username', flat=True)
hobby_members = list(hobby_members)
print(f"hobby : {hobby.name} / hobby members : {hobby_members}")
# result print
"""
hobby : 산책 / hobby members : ['user1']
hobby : 음악감상 / hobby members : ['user1', 'user2']
hobby : 스쿠버다이빙 / hobby members : ['user2']
hobby : 여행 / hobby members : ['user2']
"""
annotate, values_list 사용법
serlilzer 사용하면 대부분의 경우 대체 가능
# 이 코드를 풀어서 보도록 하자
hobby_members = list(hobby.userprofile_set.exclude(user=user).annotate(username=F('user__username')).values_list('username', flat=True))
# exclude를 사용해서 나의 취미를 제외해 준다
hobby.userprofile_set.exclude(user=user)
# userprofile의 user 필드의 username을 username안에 저장한다
hobby.userprofile_set.exclude(user=user).annotate(username=F('user__username'))
# 가져온 데이터중 username만 뽑는다
hobby.userprofile_set.exclude(user=user).annotate(username=F('user__username')).values_list('username')
# flat=True를 통해 튜플 형태의 데이터를 리스트 형식으로 바꾸어 준다. 프린트하면 쿼리셋의 리스트 형식
hobby.userprofile_set.exclude(user=user).annotate(username=F('user__username')).values_list('username', flat=True)
# 데이터가 쿼리셋 형태이므로 보기쉽게 리스트 형식으로 바꾸어 준다. 프린트 하면 그냥 리스트 형식
list(hobby.userprofile_set.exclude(user=user).annotate(username=F('user__username')).values_list('username', flat=True))
- 기타
F의 설명
# 참고로 F를 사용하려면 'import F' 를 해주어야 한다.
# F 안에 들어 있는 str을 query로 바꾸어 준다.
F('user__username')
댓글