Django Rest Framework를 사용하여 관련 모델 필드를 어떻게 포함합니까?


154

다음과 같은 모델이 있다고 가정 해 봅시다.

class Classroom(models.Model):
    room_number = [....]

class Teacher(models.Model):
    name = [...]
    tenure = [...]
    classroom = models.ForeignKey(Classroom)

ManyRelatedPrimaryKeyField 함수에 따라 다음과 같은 결과를 얻는 대신에

{
    "room_number": "42", 
    "teachers": [
        27, 
        24, 
        7
    ]
},

다음과 같은 전체 관련 모델 표현을 포함하는 것을 반환하십시오.

{
    "room_number": "42", 
    "teachers": [
        {
           'id':'27,
           'name':'John',
           'tenure':True
        }, 
        {
           'id':'24,
           'name':'Sally',
           'tenure':False
        }, 
    ]
},

이게 가능해? 그렇다면 어떻게? 그리고 이것은 나쁜 생각입니까?

답변:


242

가장 간단한 방법은 깊이 인수 를 사용 하는 것입니다

class ClassroomSerializer(serializers.ModelSerializer):
    class Meta:
        model = Classroom
        depth = 1

그러나 이는 선임 관계에 대한 관계 만 포함하며,이 경우 교사 필드는 역 관계이기 때문에 필요한 것은 아닙니다.

더 복잡한 요구 사항이있는 경우 (예 : 역 관계 포함, 일부 필드 중첩, 다른 필드 제외) 또는 특정 필드 하위 집합 만 중첩하는 경우 serializer중첩 시킬 수 있습니다 .

class TeacherSerializer(serializers.ModelSerializer):
    class Meta:
        model = Teacher
        fields = ('id', 'name', 'tenure')

class ClassroomSerializer(serializers.ModelSerializer):
    teachers = TeacherSerializer(source='teacher_set')

    class Meta:
        model = Classroom

serializer 필드에서 source 인수를 사용하여 필드의 소스로 사용할 속성을 지정하십시오. source대신 모델 teachers에서 related_name 옵션을 사용하여 속성이 있는지 확인 하여 인수를 삭제할 수 있습니다 Teacher.classroom = models.ForeignKey(Classroom, related_name='teachers')

명심해야 할 것은 중첩 된 직렬 변환기가 현재 쓰기 작업을 지원하지 않는다는 것입니다. 쓰기 가능한 표현의 경우 pk 또는 하이퍼 링크와 같은 일반적인 평면 표현을 사용해야합니다.


첫 번째 해결책을 시도했을 때 교사를받지 못했지만 교실의 부모 인스턴스를 받았습니다 (이 예제에서는 표시되지 않음). 두 번째 솔루션에서 " 'Classroom'객체에 'teachers'속성이 없습니다"라는 오류가 발생했습니다. 뭔가 빠졌습니까?
Chaz

1
@Chaz depth이 경우에 필요한 작업을 수행하지 않는 이유 와 현재보고있는 예외 및 처리 방법을 설명하기 위해 답변을 업데이트 했습니다.
Tom Christie

1
나는 바보이고 잘못된 서버를 때리고 있었다. 그것은 많은 관계에서 확실히 작동합니다.
yellottyellott

15
중첩 시리얼 라이저가 대단합니다! 나는 이것을해야했고 DRF 3.1.0을 사용하고있었습니다. 나는 many=True그렇게 포함시켜야했다 ...TeacherSerializer(source='teacher_set', many=True). 그렇지 않으면 다음과 같은 오류가 발생했습니다.The serializer field might be named incorrectly and not match any attribute or key on the 'RelatedManager' instance. Original exception text was: 'RelatedManager' object has no attribute 'type'.
Karthic Raghupathi

2
ForeignKey의 뒷면 ..._set은 기본적 으로 이름이 지정 됩니다. 자세한 내용은 Django 문서를 참조하십시오. docs.djangoproject.com/en/1.10/ref/models/relations/…
Tom Christie

36

감사합니다 @TomChristie !!! 당신은 저를 많이 도와주었습니다! 실수를했기 때문에 조금 업데이트하고 싶습니다.

class TeacherSerializer(serializers.ModelSerializer):
    class Meta:
        model = Teacher
        fields = ('id', 'name', 'tenure')

class ClassroomSerializer(serializers.ModelSerializer):
    teachers = TeacherSerializer(source='teacher_set', many=True)

    class Meta:
        model = Classroom
        field = ("teachers",)

2

이것은 drf-flex-fields 라고 불리는 매우 편리한 dandy django 패키지를 사용하여 수행 할 수도 있습니다 . 우리는 그것을 사용하고 꽤 굉장합니다. 그냥 설치하고 pip install drf-flex-fields시리얼 라이저를 통해 전달하고 추가 expandable_fields하고 빙고하십시오 (아래 예). 도트 표기법을 사용하여 깊은 중첩 관계를 지정할 수도 있습니다.

from rest_flex_fields import FlexFieldsModelSerializer

class ClassroomSerializer(FlexFieldsModelSerializer):
    class Meta:
        model = Model
        fields = ("teacher_set",)
        expandable_fields = {"teacher_set": (TeacherSerializer, {"source": "teacher_set"})}

그런 다음 ?expand=teacher_setURL에 추가 하면 확장 된 응답이 반환됩니다. 언젠가 누군가에게 도움이되기를 바랍니다. 건배!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.