Как включить связанные поля модели с помощью Django Rest Framework?

Скажем, что мы имеем следующую модель:

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
        }, 
    ]
},

Возможно ли это? Если да, то как? И это плохая идея?

Ответ 1

Самый простой способ - использовать аргумент глубины

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

Однако это будет включать только отношения для форвардных отношений, которые в этом случае не совсем то, что вам нужно, поскольку поле учителей является обратной связью.

Если у вас есть более сложные требования (например, включить обратные отношения, вложить некоторые поля, но не другие, или вложить только определенное подмножество полей), вы можете сериализаторы гнезд, например...

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

Обратите внимание, что мы используем исходный аргумент в поле сериализатора, чтобы указать атрибут для использования в качестве источника поля. Мы могли бы отказаться от аргумента source, вместо этого убедиться, что атрибут teachers существует, используя параметр related_name в вашей модели Teacher, т.е., classroom = models.ForeignKey(Classroom, related_name='teachers')

Следует иметь в виду, что вложенные сериализаторы в настоящее время не поддерживают операции записи. Для записываемых представлений вы должны использовать регулярные плоские представления, такие как pk или гиперссылка.

Ответ 2

Спасибо @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",)

Ответ 3

Это также может быть достигнуто с помощью довольно удобного Dandy django, упакованного под названием drf-flex-fields. Мы используем это, и это довольно круто. Вы просто устанавливаете его pip install drf-flex-fields, пропускаете его через ваш сериализатор, добавляете expandable_fields и bingo (пример ниже). Это также позволяет вам указывать глубокие вложенные отношения с помощью точечной нотации.

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_set к вашему URL, и он возвращает расширенный ответ. Надеюсь, это когда-нибудь кому-нибудь поможет. Ура!