Làm cách nào để bao gồm các trường mô hình liên quan bằng Django Rest Framework?


153

Hãy nói rằng chúng ta có mô hình sau:

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

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

Hãy nói rằng thay vì nhận được một kết quả như thế này theo hàm ManyRelatedPrimaryKeyField:

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

có nó trả về một cái gì đó bao gồm đại diện mô hình liên quan đầy đủ như:

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

Điều này có thể không? Nếu vậy thì thế nào? Và đây có phải là một ý tưởng tồi?

Câu trả lời:


242

Cách đơn giản nhất là sử dụng đối số độ sâu

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

Tuy nhiên, điều đó sẽ chỉ bao gồm các mối quan hệ cho các mối quan hệ chuyển tiếp, trong trường hợp này không hoàn toàn là những gì bạn cần, vì lĩnh vực giáo viên là mối quan hệ ngược lại.

Nếu bạn có các yêu cầu phức tạp hơn (ví dụ: bao gồm các mối quan hệ đảo ngược, lồng một số trường, nhưng không phải các trường khác hoặc chỉ lồng một tập hợp con cụ thể của các trường), bạn có thể lồng các tuần tự hóa , ví dụ ...

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

Lưu ý rằng chúng tôi sử dụng đối số nguồn trên trường serializer để chỉ định thuộc tính sẽ sử dụng làm nguồn của trường. Chúng ta có thể thả các sourcelập luận bằng cách thay vì đảm bảo các teachersthuộc tính tồn tại bằng cách sử dụng các related_name tùy chọn trên của bạn Teachermô hình, ví dụ.classroom = models.ForeignKey(Classroom, related_name='teachers')

Một điều cần lưu ý là các serial serial lồng nhau hiện không hỗ trợ các thao tác ghi. Đối với các biểu diễn có thể ghi, bạn nên sử dụng các biểu diễn phẳng thông thường, chẳng hạn như pk hoặc siêu liên kết.


Khi tôi thử giải pháp đầu tiên, tôi đã không nhận được Giáo viên, tuy nhiên tôi đã nhận được các trường hợp của phụ huynh Lớp học (ví dụ này không hiển thị). Trong giải pháp thứ hai, tôi đã nhận được một lỗi - đối tượng "'Lớp học' không có thuộc tính 'giáo viên'". Tui bỏ lỡ điều gì vậy?
Chaz

1
@Chaz Cập nhật câu trả lời để giải thích lý do tại sao depthbạn không làm những gì bạn cần trong trường hợp này và để giải thích ngoại lệ bạn đang thấy và cách xử lý.
Tom Christie

1
Tôi là một thằng ngốc và đã đánh nhầm máy chủ. Nó chắc chắn hoạt động trên nhiều mối quan hệ.
yellottyellott

15
Nest serial serial là tuyệt vời! Tôi đã phải làm điều này và đã sử dụng DRF 3.1.0. Tôi đã phải bao gồm many=Truenhư vậy ...TeacherSerializer(source='teacher_set', many=True). Nếu không, tôi đã nhận được lỗi sau: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
Mặt trái của ForeignKey sẽ được đặt tên ..._settheo mặc định. Xem tài liệu Django để biết thêm chi tiết: docs.djangoproject.com/en/1.10/ref/models/relations/ chủ
Tom Christie

36

Cảm ơn bạn @TomChristie !!! Bạn đã giúp tôi rất nhiều! Tôi muốn cập nhật một chút (vì một lỗi tôi gặp phải)

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

Điều này cũng có thể được thực hiện bằng cách sử dụng một django dandy khá tiện dụng được đóng gói được gọi là drf-flex-field . Chúng tôi sử dụng nó và nó khá tuyệt vời. Bạn chỉ cần cài đặt nó pip install drf-flex-fields, chuyển nó qua serializer của bạn, thêm expandable_fieldsvà bingo (ví dụ dưới đây). Nó cũng cho phép bạn chỉ định các mối quan hệ lồng nhau sâu bằng cách sử dụng ký hiệu dấu chấm.

from rest_flex_fields import FlexFieldsModelSerializer

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

Sau đó, bạn thêm ?expand=teacher_setvào URL của mình và nó trả về một phản hồi mở rộng. Hy vọng điều này sẽ giúp ai đó, một ngày nào đó. Chúc mừng!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.