Django Rest Framework kullanarak ilgili model alanlarını nasıl eklerim?


154

Diyelim ki aşağıdaki modele sahibiz:

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

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

Diyelim ki ManyRelatedPrimaryKeyField işlevi için böyle bir sonuç almak yerine:

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

aşağıdaki gibi tam ilgili model temsilini içeren bir şey döndürmesini sağlayın:

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

Mümkün mü? Öyleyse nasıl? Ve bu kötü bir fikir mi?

Yanıtlar:


242

En basit yol derinlik argümanını kullanmaktır

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

Bununla birlikte, bu sadece öğretmenler alanı ters bir ilişki olduğundan, bu durumda ihtiyacınız olan şey değil, ileri ilişkiler için ilişkileri içerecektir.

Daha karmaşık gereksinimleriniz varsa (ör. Ters ilişkileri dahil edin, bazı alanları iç içe geçirin, ancak diğerlerini değil veya yalnızca belirli bir alan alt kümesini iç içe geçirin ) serileştiricileri iç içe ...

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

Alanın kaynağı olarak kullanılacak özniteliği belirtmek için serileştirici alanındaki kaynak bağımsız değişkenini kullandığımızı unutmayın. sourceBunun yerine , modelinizdeki related_name seçeneğini teacherskullanarak özniteliğin var olduğundan emin olarak argümanı bırakabiliriz .Teacherclassroom = models.ForeignKey(Classroom, related_name='teachers')

Akılda tutulması gereken bir şey, iç içe serileştiricilerin şu anda yazma işlemlerini desteklememesidir. Yazılabilir temsiller için, pk veya hyperlinking gibi düzenli düz temsiller kullanmalısınız.


İlk çözümü denediğimde Öğretmenleri almadım, ancak Classroom'un ebeveyninin örneklerini aldım (bu örnekte gösterilmiyor). İkinci çözümde bir hata aldım - "'Classroom' nesnesinin 'öğretmenler' özelliği yok. Bir şey mi kaçırıyorum?
Chaz

1
@Chaz depthBu durumda neden ihtiyaç duymadığınızı açıklamak ve gördüğünüz istisnayı ve bununla nasıl başa çıkacağınızı açıklamak için cevabı güncelleyin .
Tom Christie

1
Ben bir aptalım ve yanlış sunucuya vuruyordum. Kesinlikle pek çok ilişkide çalışır.
yellottyellott

15
Serileştiricileri yuvalamak harika! Bunu yapmak zorundaydım ve DRF 3.1.0 kullanıyordum. many=TrueBöyle dahil etmek zorunda kaldım ...TeacherSerializer(source='teacher_set', many=True). Aksi takdirde şu hatayı alıyordum:The serializer field might be named incorrectly and not match any attribute or key on the 'RelatedManager' instance. Original exception text was: 'RelatedManager' object has no attribute 'type'.
Karthic Raghupathi

2
Bir ForeignKey öğesinin arka yüzü ..._setvarsayılan olarak adlandırılacaktır . Daha fazla ayrıntı için Django belgelerine bakın: docs.djangoproject.com/en/1.10/ref/models/relations/…
Tom Christie

36

Teşekkür ederim @ TomChristie !!! Bana çok yardımcı oldun! Bunu biraz güncellemek istiyorum (karşılaştığım bir hata nedeniyle)

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

2

Bu, drf-flex-fields adlı paketlenmiş oldukça kullanışlı bir züppe django kullanılarak da gerçekleştirilebilir . Onu kullanıyoruz ve oldukça harika. Sadece kurun pip install drf-flex-fields, serileştiricinizden geçirin, ekleyin expandable_fieldsve tombala (aşağıdaki örnek). Ayrıca nokta gösterimini kullanarak derin iç içe ilişkiler belirtmenizi sağlar.

from rest_flex_fields import FlexFieldsModelSerializer

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

Ardından ?expand=teacher_setURL'nize eklersiniz ve genişletilmiş bir yanıt döndürür. Umarım bu birisine yardım eder, bir gün. Şerefe!

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.