Django-rest-çerçeve serileştiricileriyle bir Yabancı Anahtar değeri alma


89

Bir API oluşturmak için django dinlenme çerçevesini kullanıyorum. Aşağıdaki modellere sahibim:

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

Yapacağım kategoriler için bir serileştirici oluşturmak için:

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

    class Meta:
        model = Category

... ve bu bana şunları sağlayacaktır:

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

Bir Öğe serileştiriciden tersini nasıl alabilirim, yani:

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

Geri kalan çerçeve için ters ilişkiler hakkındaki dokümanları okudum, ancak bu, ters olmayan alanlarla aynı sonuç gibi görünüyor. Bariz bir şeyi mi kaçırıyorum?

Yanıtlar:


85

Ayar yapmadan sadece ilgili bir alanı kullanın many=True.

Ayrıca çıktının adlandırılmasını istediğiniz için category_name, ancak asıl alan serileştirici alanındaki bağımsız değişkeni categorykullanmanız gerektiğini unutmayın source.

Aşağıdakiler size ihtiyacınız olan çıktıyı vermelidir ...

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

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

21
kategori modelinin tüm alanlarını geri almaya ne dersiniz?
AJ

12
kategori modelinin tüm alanlarını geri almak istiyorsanız kategori serileştiriciyi yapın ve kategori_adı = CategorySerliazer ()
Faizan Ali

7
Bunu yapmaya çalıştım ama bir hata alıyorum Relational field must provide a 'queryset' argument, or set read_only='True'
ePascoal

veya oluşturmayı / güncellemeyi desteklemek istiyorsanız bir sorgu kümesi özniteliği sağlamak, şuna benzer bir şey: category_name = serializers.RelatedField(source='category', queryset=Category.objects.all()) Sanırım.
stelios

1
AssertionError:...Bu yanıtı alırsanız stackoverflow.com/a/44530606/5403449
Josh

86

DRF 3.6.3 sürümünde bu benim için çalıştı

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

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

Daha fazla bilgiyi burada bulabilirsiniz: Serileştirici Alanları temel argümanları


Ancak eşya olmalısınız çünkü Öğe modelindeki kategori alanı boş olarak ayarlanmışsa NoneType hatası vermelidir = True
Desert Camel

29

Yapabileceğiniz başka bir şey şudur:

  • Itemmodelinizde kategori adını döndüren bir özellik oluşturun ve
  • bir ReadOnlyField.

Modeliniz böyle görünecektir.

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

Serileştiriciniz şöyle görünecektir. Serileştiricinin category_name, alanı aynı adla adlandırarak model özelliğinin değerini otomatik olarak alacağını unutmayın .

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

    class Meta:
        model = Item

18

bu benim için iyi çalıştı:

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

9

08/08/2018 ve DRF 3.8.2 sürümünde çalıştı:

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

read_only_fieldsMeta'yı kullanarak tam olarak hangi alanların salt okunur olacağını bildirebiliriz. Sonra foreignMeta'daki alanı bildirmemiz gerekir fields(mantra şöyle açık olsun: python'un zen'i ).


6

Yabancı anahtarın ve özniteliğinin source='category.name'olduğu basit çözüm .category.name

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__"

0

Bu çözüm, kaynak modeli tanımlamaya gerek olmadığı için daha iyidir. Ancak serileştirici alanının adı, yabancı anahtar alan adıyla aynı olmalıdır

class ItemSerializer(serializers.ModelSerializer):
    category = serializers.SlugRelatedField(read_only=True, slug_field='title')

    class Meta:
        model = Item
        fields = ('id', 'name', 'category')
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.