148 votes

Récupération d'une valeur de clé étrangère avec les sérialiseurs de django-rest-framework

J'utilise le framework django rest pour créer une API. J'ai les modèles suivants :

class Category(models.Model):
    name = models.CharField(max_length=100)

    def __unicode__(self):
        return self.name

class Item(models.Model):
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, related_name='items')

    def __unicode__(self):
        return self.name

Pour créer un sérialiseur pour les catégories, je ferais :

class CategorySerializer(serializers.ModelSerializer):
    items = serializers.RelatedField(many=True)

    class Meta:
        model = Category

... et cela me fournirait :

[{'items': [u'Item 1', u'Item 2', u'Item 3'], u'id': 1, 'name': u'Cat 1'},
 {'items': [u'Item 4', u'Item 5', u'Item 6'], u'id': 2, 'name': u'Cat 2'},
 {'items': [u'Item 7', u'Item 8', u'Item 9'], u'id': 3, 'name': u'Cat 3'}]

Comment faire pour obtenir l'inverse à partir d'un sérialiseur d'éléments, par exemple :

[{u'id': 1, 'name': 'Item 1', 'category_name': u'Cat 1'},
{u'id': 2, 'name': 'Item 2', 'category_name': u'Cat 1'},
{u'id': 3, 'name': 'Item 3', 'category_name': u'Cat 1'},
{u'id': 4, 'name': 'Item 4', 'category_name': u'Cat 2'},
{u'id': 5, 'name': 'Item 5', 'category_name': u'Cat 2'},
{u'id': 6, 'name': 'Item 6', 'category_name': u'Cat 2'},
{u'id': 7, 'name': 'Item 7', 'category_name': u'Cat 3'},
{u'id': 8, 'name': 'Item 8', 'category_name': u'Cat 3'},
{u'id': 9, 'name': 'Item 9', 'category_name': u'Cat 3'}]

J'ai lu les documents sur relations inversées pour le cadre de repos, mais cela semble être le même résultat que pour les champs non inversés. Est-ce que je rate quelque chose d'évident ?

179voto

Sayok88 Points 500

Dans la version 3.6.3 du DRF, cela a fonctionné pour moi.

class ItemSerializer(serializers.ModelSerializer):
    category_name = serializers.CharField(source='category.name')

    class Meta:
        model = Item
        fields = ('id', 'name', 'category_name')

Vous trouverez plus d'informations ici : Arguments principaux de Serializer Fields

122voto

Tom Christie Points 8729

Utilisez simplement un champ connexe sans définir many=True .

Notez que même si vous voulez que la sortie soit nommée category_name mais le champ réel est category vous devez utiliser l'option source sur le champ du sérialiseur.

Ce qui suit devrait vous donner les résultats dont vous avez besoin...

class ItemSerializer(serializers.ModelSerializer):
    category_name = serializers.RelatedField(source='category', read_only=True)

    class Meta:
        model = Item
        fields = ('id', 'name', 'category_name')

42voto

hsebastian Points 116

Une autre chose que vous pouvez faire est de :

  • créer une propriété dans votre Item qui renvoie le nom de la catégorie et
  • l'exposer comme un ReadOnlyField .

Votre modèle ressemblerait à ceci.

class Item(models.Model):
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, related_name='items')

    def __unicode__(self):
        return self.name

    @property
    def category_name(self):
        return self.category.name

Votre sérialiseur ressemblerait à ceci. Notez que le sérialiseur obtiendra automatiquement la valeur de la balise category_name en nommant le champ avec le même nom.

class ItemSerializer(serializers.ModelSerializer):
    category_name = serializers.ReadOnlyField()

    class Meta:
        model = Item

30voto

suhail Points 2520

Cela a bien fonctionné pour moi :

class ItemSerializer(serializers.ModelSerializer):
    category_name = serializers.ReadOnlyField(source='category.name')
    class Meta:
        model = Item
        fields = "__all__"

18voto

Anurag Misra Points 728

Une solution simple source='category.name' donde category est une clé étrangère et .name c'est un attribut.

from rest_framework.serializers import ModelSerializer, ReadOnlyField
from my_app.models import Item

class ItemSerializer(ModelSerializer):
    category_name = ReadOnlyField(source='category.name')

    class Meta:
        model = Item
        fields = "__all__"

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X