wake-up-neo.com

Abrufen eines Fremdschlüsselwerts mit Django-Rest-Framework-Serialisierern

Ich benutze das Django Rest Framework, um eine API zu erstellen. Ich habe die folgenden Modelle:

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

So erstellen Sie ein Serialisierungsprogramm für die Kategorien:

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

    class Meta:
        model = Category

... und das würde mich versorgen mit:

[{'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'}]

Wie würde ich vorgehen, um das Gegenteil von einem Artikel-Serialisierer zu erhalten, dh:

[{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'}]

Ich habe die Dokumentation zu mgekehrte Beziehungen für das restliche Framework gelesen, aber das scheint dasselbe Ergebnis zu sein wie bei den nicht umgekehrten Feldern. Vermisse ich etwas Offensichtliches?

51
hellsgate

Verwenden Sie einfach ein verwandtes Feld, ohne many=True.

Beachten Sie dies auch, weil Sie die Ausgabe mit dem Namen category_name, aber das aktuelle Feld ist category, Sie müssen das Argument source für das Serializer-Feld verwenden.

Das Folgende sollte Ihnen die Ausgabe geben, die Sie benötigen ...

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

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

In der aktuellen DRF (3.6.3) -Version funktionierte dies für mich

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

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

Eine andere Sache, die Sie tun können, ist:

  • erstellen Sie eine Eigenschaft in Ihrem Item Modell, die den Kategorienamen und zurückgibt
  • mach es als ReadOnlyField verfügbar.

Ihr Modell würde so aussehen.

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

Ihr Serializer würde so aussehen. Beachten Sie, dass der Serializer automatisch den Wert der Modelleigenschaft category_name Erhält, indem er das gleichnamige Feld benennt.

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

    class Meta:
        model = Item
20
hsebastian

das hat gut funktioniert für mich:

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

Arbeitete am 08/08/2018 und an der DRF-Version 3.8.2:

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',)

Verwendung des Meta read_only_fields Wir können genau festlegen, welche Felder nur lesbar sein sollen. Dann müssen wir das Feld foreign im Meta fields deklarieren (besser explizit, wie das Mantra lautet: Zen von Python ).

4
John Moutafis

Einfache Lösung source='category.name' wobei category Fremdschlüssel ist und .name es ist 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__
2
Anurag Misra