Як включити відповідні поля моделей за допомогою програми 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

Однак це стосуватиметься лише відносин для прямих відносин, що в даному випадку не зовсім те, що потрібно, оскільки поле викладачів - це зворотні відносини.

Якщо у вас є складніші вимоги (наприклад, включайте зворотні зв'язки, вкладайте деякі поля, але не інші, або вкладайте лише певну підмножину полів), ви можете вкласти серіалізатори , наприклад ...

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 або гіперпосилання.


Коли я спробував перше рішення, я не отримав вчителів, однак отримав екземпляри батьків класу (чого цей приклад не показує). У другому рішенні я отримав помилку - об’єкт "Клас" не має атрибута "викладачі" ". Я щось пропускаю?
Чаз

1
@Chaz Оновлено відповідь, щоб пояснити, чому depthв цьому випадку не робити того, що вам потрібно, і пояснити виняток, який ви бачите, і як з цим боротися.
Том Крісті

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/…
Том Крісті,

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-polja . Ми використовуємо це, і це досить приголомшливо. Ви просто встановите його 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_setдо своєї URL-адреси, і вона повертає розширену відповідь. Сподіваюся, це допоможе комусь, коли-небудь. Ура!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.