web-dev-qa-db-fra.com

Comment inclure des champs de modèle associés à l’aide de Django Rest Framework?)

Disons que nous avons le modèle suivant:

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

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

Disons qu'au lieu d'obtenir un résultat comme celui-ci selon la fonction ManyRelatedPrimaryKeyField:

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

faites-le retourner quelque chose qui inclut la représentation complète du modèle associé, comme:

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

Est-ce possible? Si c'est le cas, comment? Et est-ce une mauvaise idée?

132
Chaz

Le moyen le plus simple consiste à utiliser l'argument de profondeur

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

Cependant, cela n'inclura que les relations pour les relations en aval, ce qui dans ce cas n'est pas tout à fait ce dont vous avez besoin, car le champ des enseignants est une relation inverse.

Si vous avez des exigences plus complexes (par exemple, inclure des relations inverses, imbriquer certains champs, mais pas d'autres, ou imbriquer seulement un sous-ensemble spécifique de champs), vous pouvez imbriquer des sérialiseurs , par exemple ...

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

Notez que nous utilisons l'argument source sur le champ du sérialiseur pour spécifier l'attribut à utiliser comme source du champ. Nous pourrions supprimer l'argument source en nous assurant plutôt que l'attribut teachers existe en utilisant l'option nom_relié sur votre modèle Teacher, c'est-à-dire. classroom = models.ForeignKey(Classroom, related_name='teachers')

Il convient de garder à l'esprit que les sérialiseurs imbriqués ne prennent actuellement pas en charge les opérations d'écriture. Pour les représentations en écriture, vous devez utiliser des représentations à plat régulières, telles que pk ou hyperlien.

211
Tom Christie

Merci @ TomChristie !!! Tu m'as beaucoup aidé! Je voudrais mettre à jour un peu cela (à cause d'une erreur que j'ai commise)

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",)
30
Eliyahu Tauber

Ceci peut aussi être accompli en utilisant un dandy très pratique Django emballé appelé drf-flex-fields . Nous l'utilisons et c'est vraiment génial. Vous venez de l'installer pip install drf-flex-fields, passez-le dans votre sérialiseur, ajoutez expandable_fields et bingo (exemple ci-dessous). Il vous permet également de spécifier des relations imbriquées profondes à l'aide de la notation par points.

from rest_flex_fields import FlexFieldsModelSerializer

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

Ensuite, vous ajoutez ?expand=teacher_set à votre URL et renvoie une réponse développée. J'espère que cela aidera quelqu'un, un jour. À votre santé!

0
Paul Tuckett