ฉันจะรวมฟิลด์โมเดลที่เกี่ยวข้องโดยใช้ Django Rest Framework ได้อย่างไร


154

สมมติว่าเรามีรูปแบบต่อไปนี้:

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

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

สมมติว่าแทนที่จะได้ผลลัพธ์เช่นนี้ต่อฟังก์ชัน ManyRelatedPrimaryKeyField:

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

มันจะคืนสิ่งที่มีการเป็นตัวแทนรูปแบบที่เกี่ยวข้องเช่น:

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

เป็นไปได้ไหม ถ้าเป็นเช่นนั้นได้อย่างไร และนี่เป็นความคิดที่ไม่ดีเหรอ?

คำตอบ:


242

วิธีที่ง่ายที่สุดคือใช้อาร์กิวเมนต์ความลึก

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

อย่างไรก็ตามนั่นจะรวมถึงความสัมพันธ์สำหรับความสัมพันธ์แบบส่งต่อซึ่งในกรณีนี้ไม่ใช่สิ่งที่คุณต้องการเนื่องจากเขตข้อมูลของครูเป็นความสัมพันธ์แบบย้อนกลับ

หากคุณมีข้อกำหนดที่ซับซ้อนมากขึ้น (เช่นรวมถึงความสัมพันธ์แบบย้อนกลับทำรังบางฟิลด์ แต่ไม่ใช่ข้อกำหนดอื่นหรือซ้อนเฉพาะบางส่วนของฟิลด์) คุณสามารถซ้อน Serializersเช่น ...

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

โปรดทราบว่าเราใช้อาร์กิวเมนต์แหล่งที่มาในเขตข้อมูล serializer เพื่อระบุคุณสมบัติที่จะใช้เป็นแหล่งที่มาของสนาม เราสามารถทำการsourceโต้แย้งโดยทำให้แน่ใจว่าteachersแอตทริบิวต์นั้นมีอยู่โดยใช้ตัวเลือกrelated_nameในTeacherแบบจำลองของคุณเช่นclassroom = models.ForeignKey(Classroom, related_name='teachers')

สิ่งหนึ่งที่ต้องจำไว้คือ serializers ที่ซ้อนกันไม่สนับสนุนการเขียนในปัจจุบัน สำหรับการนำเสนอที่เขียนได้คุณควรใช้การนำเสนอแบบปกติเช่น pk หรือไฮเปอร์ลิงก์


เมื่อฉันลองวิธีแก้ปัญหาแรกฉันไม่ได้รับอาจารย์อย่างไรก็ตามฉันได้รับอินสแตนซ์ของผู้ปกครองของห้องเรียน (ซึ่งตัวอย่างนี้ไม่แสดง) ในวิธีที่สองฉันได้รับข้อผิดพลาด - "วัตถุ 'ห้องเรียน' ไม่มีแอตทริบิวต์ 'ครู'" ฉันพลาดอะไรไปรึเปล่า?
Chaz

1
@Chaz แก้ไขคำตอบเพื่ออธิบายว่าทำไมdepthไม่ทำสิ่งที่คุณต้องการในกรณีนี้และอธิบายข้อยกเว้นที่คุณเห็นและวิธีจัดการกับมัน
Tom Christie

1
ฉันเป็นคนงี่เง่าและชนเซิร์ฟเวอร์ผิด มันใช้งานได้จริงในหลาย ๆ ความสัมพันธ์
yellottyellott

15
Serializers รังที่น่ากลัว! ฉันต้องทำสิ่งนี้และใช้ DRF 3.1.0 ฉันมีการรวมเช่นดังนั้นmany=True ...TeacherSerializer(source='teacher_set', many=True)มิฉะนั้นฉันได้รับข้อผิดพลาดต่อไปนี้: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
ด้านหลังของ ForeignKey จะถูกตั้งชื่อ..._setตามค่าเริ่มต้น ดูเอกสาร Django สำหรับรายละเอียดเพิ่มเติมได้ที่: docs.djangoproject.com/en/1.10/ref/models/relations/ …
Tom Christie

36

ขอบคุณ @TomChristie !!! คุณช่วยฉันมาก! ฉันต้องการอัปเดตเล็กน้อย (เนื่องจากความผิดพลาดที่ฉันพบ)

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

นอกจากนี้ยังสามารถทำได้โดยใช้ Django สำรวยประโยชน์สวยแพคเกจที่เรียกว่าDRF-Flex เขต เราใช้มันและมันก็สวยมาก คุณเพิ่งติดตั้งpip install drf-flex-fieldsผ่านมันผ่าน serializer ของคุณเพิ่มexpandable_fieldsและ bingo (ตัวอย่างด้านล่าง) นอกจากนี้ยังช่วยให้คุณระบุความสัมพันธ์ที่ซ้อนกันเชิงลึกโดยใช้เครื่องหมายจุด

from rest_flex_fields import FlexFieldsModelSerializer

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

จากนั้นคุณเพิ่มลง?expand=teacher_setใน URL ของคุณและจะส่งคืนการตอบกลับที่ขยายเพิ่ม หวังว่าสิ่งนี้จะช่วยให้ใครบางคนสักวันหนึ่ง ไชโย!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.