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 que 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 puis-je obtenir l'inverse d'un sérialiseur d'élément, à savoir:
[{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 la documentation sur relations inverses pour le reste de la structure, mais cela semble être le même résultat que les champs non inversés. Est-ce que je manque quelque chose d'évident?
Il suffit d'utiliser un champ associé sans définir many=True
.
Notez aussi que vous voulez que la sortie nommée category_name
, mais le champ réel est category
, vous devez utiliser l’argument source
sur le champ du sérialiseur.
Ce qui suit devrait vous donner la sortie 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')
Dans la version actuelle de DRF (3.6.3) 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')
Une autre chose que vous pouvez faire est de:
Item
qui renvoie le nom de la catégorie etReadOnlyField
.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 du category_name
propriété du modèle en nommant le champ avec le même nom.
class ItemSerializer(serializers.ModelSerializer):
category_name = serializers.ReadOnlyField()
class Meta:
model = Item
cA marchait bien pour moi:
class ItemSerializer(serializers.ModelSerializer):
category_name = serializers.ReadOnlyField(source='category.name')
class Meta:
model = Item
fields = "__all__"
Travaillé le 08/08/2018 et sur la version 3.8.2 de DRF:
class ItemSerializer(serializers.ModelSerializer):
category_name = serializers.ReadOnlyField(source='category.name')
class Meta:
model = Item
read_only_fields = ('id', 'category_name')
fields = ('id', 'category_name', 'name',)
Utiliser le Meta read_only_fields
_ nous pouvons déclarer exactement quels champs doivent être read_only. Ensuite, nous devons déclarer le champ foreign
sur la méta fields
(mieux vaut être explicite comme le mantra le dit: zen of python ).
Solution simple source='category.name'
où category
est la clé étrangère et .name
c'est l'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__