본문 바로가기
스파르타코딩 AI웹개발 3기

내일배움캠프_TIL_2022.12.07

by 청귤에이드 2022. 12. 7.

drf 정참조 역참조 개념이 아직도 헷갈려서 자료를 수집하고 있는 중인데

 

'분명 맞는 것 같은데 100% 확신하기는 어려움' 으로 정리할 수 밖에 없어서 이후에 개념이 더 명확해 지면 다시 정리하려고 합니다.

 

# workshops/serializers.py

class HobbySerializer(serializers.ModelSerializer):
    class Meta:
        model = Hobby
        fields = '__all__'
        
        
class SelectedHobbySerializer(serializers.ModelSerializer): # 마이페이지 - 내가 선택한 취미
    # hobby = serializers.StringRelatedField(many=True) # pk값 제외하고 string 데이터만 불러올때
    # category = HobbySerializer(many=True) # 틀린 예
    hobby = HobbySerializer(many=True)
    class Meta:
        model = User
        fields = ('hobby',)


class AppliedWorkshopSerializer(serializers.ModelSerializer): # 마이페이지 - 신청 워크샵
    member = WorkshopListSerializer(many=True)
    class Meta:
        model = User
        fields = ('member',) # (이후 변경 예정)


class CreatedWorkshopSerializer(serializers.ModelSerializer): # 마이페이지 - 생성 워크샵
    workshop_host = WorkshopListSerializer(many=True)
    class Meta:
        model = User
        fields = ('workshop_host',)  # (이후 변경 예정)

 

두 번째 'SelectedHobbySerializer'에서는 User 모델을 기반으로 하지만, 'hobby'에 대한 정보를 출력하고자 하기 때문에 fileds에 'hobby'를 추가하였고, HobbySerializer를 통해 'Hobby'모델을 사용하는 것을 알 수 있습니다. Hobby 모델에서는 User모델과 연결된 변수가 없기 때문에 정참조 관계이고, 정참조 시 타 모델을 가져올땐 모델명(소문자)로 기입하므로 Hobby의 소문자인 hobby로 반드시 명명해야 합니다.

 

hobby 위에 주석 처리된 #hobby와 #category에 대해 살펴보면, #hobby는 맞는 예지만 pk 값 없이 string 데이터만 필요할 때, StringRelatedField를 사용한 것이고, #category는 정참조의 경우는 처음에 Hobby 모델 안에 있는 변수명을 기입해야 하는 것으로 잘못 이해했어서 시간을 많이 허비했는데 반드시 유의하고 넘어가야할 부분이라 생각해서 적어봤습니다.

 

세번째 AppliedWorkshopSerializer와 CreatedWorkshopSerializer에서는 변수명을 각각 member, workshop_host라고 표기한 것을 볼 수 있는데, 이는 Workshop 모델을 바탕으로 한 serializer이기 때문에 User와 역참조 관계에 있는 Workshop모델의 변수를 가져오기 위해서 related_name 을 사용한 것입니다.

 

역참조 시, related_name 없이 디폴트로 '(모델명 소문자)_set' 로 표시해도 되지만 여기서 주의할 점은,  '(모델명 소문자)_set'을 사용하기 위해서는 User모델과 Workshop 모델에 연결된 Foreignkey가 1개만 있어야 합니다. (사실 이 부분이 좀 명확하지 않지만 이것말고는 설명할 수 있는 원인이 없어서.. 이후에 다시 정확하게 정리하겠습니다) 실제로 member  대신 workshop_set를 적어서 테스트 해보면 속성값 오류가 나오는 것을 확인할 수 있습니다.

 

아래는 workshops앱에 있는 모델입니다.

# workshops/models.py

class Hobby(models.Model):
    category = models.CharField(max_length=10)

    def __str__(self):
        return str(self.category)


class Location(models.Model):
    district = models.CharField(max_length=20)

    def __str__(self):
        return str(self.district)


class Workshop(models.Model):
    category = models.ForeignKey(Hobby, on_delete=models.CASCADE, related_name='workshop_category')
    host = models.ForeignKey(User, on_delete=models.CASCADE, related_name='workshop_host')
    date = models.DateTimeField()
    location = models.ForeignKey(Location, on_delete=models.CASCADE)
    address = models.CharField(max_length=20)
    title = models.CharField(max_length=20)
    content = models.TextField(max_length=500)
    workshop_image = models.ImageField(upload_to='workshop/')
    max_client = models.IntegerField()
    amount = models.DecimalField(decimal_places=0, max_digits=10000000000000000)
    created_at = models.DateTimeField(auto_now_add=True)
    participant = models.ManyToManyField(User, related_name='member', symmetrical=False, blank=True)
    likes = models.ManyToManyField(User, related_name='workshop_likes')
    
    def __str__(self):
        return self.title