Bao gồm trung gian (thông qua mô hình) trong các phản hồi trong Django Rest Framework


110

Tôi có một câu hỏi về việc xử lý các mô hình m2m / through và cách trình bày của chúng trong khuôn khổ phần còn lại django. Hãy lấy một ví dụ cổ điển:

models.py:

from django.db import models

class Member(models.Model):
    name = models.CharField(max_length = 20)
    groups = models.ManyToManyField('Group', through = 'Membership')

class Group(models.Model):
    name = models.CharField(max_length = 20)

class Membership(models.Model):
    member = models.ForeignKey('Member')
    group = models.ForeignKey('Group')
    join_date = models.DateTimeField()

serializers.py:

imports...

class MemberSerializer(ModelSerializer):
    class Meta:
        model = Member

class GroupSerializer(ModelSerializer):
    class Meta:
        model = Group

views.py:

imports...

class MemberViewSet(ModelViewSet):
    queryset = Member.objects.all()
    serializer_class = MemberSerializer

class GroupViewSet(ModelViewSet):
    queryset = Group.objects.all()
    serializer_class = GroupSerializer

Khi NHẬN một phiên bản của Thành viên, tôi nhận thành công tất cả các trường của thành viên và cả các nhóm của nó - tuy nhiên tôi chỉ nhận được thông tin chi tiết của các nhóm mà không có thêm chi tiết nào đến từ mô hình Thành viên.

Nói cách khác, tôi mong đợi nhận được:

{
   'id' : 2,
   'name' : 'some member',
   'groups' : [
      {
         'id' : 55,
         'name' : 'group 1'
         'join_date' : 34151564
      },
      {
         'id' : 56,
         'name' : 'group 2'
         'join_date' : 11200299
      }
   ]
}

Lưu ý join_date .

Tôi đã thử rất nhiều giải pháp, tất nhiên bao gồm cả trang chính thức của Django Rest-Framework về nó và dường như không ai đưa ra câu trả lời rõ ràng thích hợp về nó - tôi cần làm gì để thêm những trường bổ sung này? Tôi thấy nó dễ dàng hơn với django-ngonypie nhưng có một số vấn đề khác và thích khuôn khổ nghỉ ngơi hơn.



8
Đây là một chiếc bánh ngon, tôi đang làm việc với Django Rest Framework.
mllm

Câu trả lời:


139

Làm thế nào về.....

Trên MemberSerializer của bạn, xác định một trường trên đó như:

groups = MembershipSerializer(source='membership_set', many=True)

và sau đó trên serializer thành viên của bạn, bạn có thể tạo:

class MembershipSerializer(serializers.HyperlinkedModelSerializer):

    id = serializers.Field(source='group.id')
    name = serializers.Field(source='group.name')

    class Meta:
        model = Membership

        fields = ('id', 'name', 'join_date', )

Điều đó có tác dụng tổng thể là tạo ra một giá trị được tuần tự hóa, các nhóm, có nguồn gốc là thành viên bạn muốn và sau đó nó sử dụng bộ tuần tự hóa tùy chỉnh để lấy ra các bit bạn muốn hiển thị.

CHỈNH SỬA: như nhận xét của @bryanph, serializers.fieldđã được đổi tên thành serializers.ReadOnlyFieldtrong DRF 3.0, vì vậy điều này nên đọc:

class MembershipSerializer(serializers.HyperlinkedModelSerializer):

    id = serializers.ReadOnlyField(source='group.id')
    name = serializers.ReadOnlyField(source='group.name')

    class Meta:
        model = Membership

        fields = ('id', 'name', 'join_date', )

cho bất kỳ triển khai hiện đại nào


2
fyi, tôi đã thử nhiều biến thể của cái này và tôi không thể làm cho nó hoạt động. Điều này không có trong tài liệu chính thức? Member_set được định nghĩa ở đâu?
đất sét

3
membership_setlà tên liên quan mặc định cho Thành viên -> Tư cách thành viên
dustinfarris

Phần mẹo đối với tôi là phát hiện ra tên "Member_set". Tôi đã có một mô hình thông qua không có tên rõ ràng "có liên quan", vì vậy tôi phải đoán tên của nó, bằng cách đọc các tài liệu tại Django Many to Many .
mouseno

điều này làm việc tuyệt vời, cảm ơn vì gợi ý. Tuy nhiên, tôi nghĩ DRF trong trường hợp này hơi phản trực giác vì Class Member đã định nghĩa một trường m2m được gọi là nhóm và giải pháp này dường như ghi đè trường trong bộ tuần tự bằng cách buộc nó trỏ đến mối quan hệ ngược lại từ mô hình thông qua. Tôi không hiểu nhiều về chi tiết triển khai DRF, nhưng có lẽ với việc xem xét mô hình, nó có thể được đưa ra tự động. chỉ là một số thức ăn để suy nghĩ :)
gru

Bất kỳ trường hợp nào, bạn có thể cập nhật cho chúng tôi xem điều này có hoạt động với phiên bản DRF mới nhất không? Hoặc ít nhất cho biết bạn đang sử dụng phiên bản nào? Tôi không thể tạo DRF để trả về mô hình trường thông qua - nó luôn kết thúc với quan hệ ban đầu (thay vì Tư cách thành viên - nó sẽ luôn trả về Nhóm).
Andrey Cizov

18

Tôi đang đối mặt với vấn đề này và giải pháp của tôi (sử dụng DRF 3.6) là sử dụng SerializerMethodField trên đối tượng và truy vấn rõ ràng bảng Thành viên như sau:

class MembershipSerializer(serializers.ModelSerializer):
    """Used as a nested serializer by MemberSerializer"""
    class Meta:
        model = Membership
        fields = ('id','group','join_date')

class MemberSerializer(serializers.ModelSerializer):
    groups = serializers.SerializerMethodField()

    class Meta:
        model = Member
        fields = ('id','name','groups')

    def get_groups(self, obj):
        "obj is a Member instance. Returns list of dicts"""
        qset = Membership.objects.filter(member=obj)
        return [MembershipSerializer(m).data for m in qset]

Thao tác này sẽ trả về danh sách các phần cho khóa nhóm trong đó mỗi câu chính tả được tuần tự hóa từ MemberhipSerializer. Để làm cho nó có thể ghi được, bạn có thể xác định phương thức tạo / cập nhật của riêng bạn bên trong MemberSerializer nơi bạn lặp lại dữ liệu đầu vào và tạo hoặc cập nhật rõ ràng các cá thể của mô hình Thành viên.


-4

LƯU Ý: Là một kỹ sư phần mềm, tôi thích sử dụng Kiến trúc và tôi đã nghiên cứu sâu về Phương pháp tiếp cận theo lớp để phát triển, vì vậy tôi sẽ trả lời nó với sự tôn trọng đối với các cấp.

Như tôi đã hiểu Vấn đề, Đây là mô hình Giải pháp.py

class Member(models.Model):
    member_id = models.AutoField(primary_key=True)
    member_name = models.CharField(max_length = 

class Group(models.Model):
    group_id = models.AutoField(primary_key=True)
    group_name = models.CharField(max_length = 20)
    fk_member_id = models.ForeignKey('Member', models.DO_NOTHING, 
                             db_column='fk_member_id', blank=True, null=True)

class Membership(models.Model):
    membershipid = models.AutoField(primary_key=True)
    fk_group_id = models.ForeignKey('Group', models.DO_NOTHING, 
                             db_column='fk_member_id', blank=True, null=True)
    join_date = models.DateTimeField()

serializers.py

import serializer

class AllSerializer(serializer.Serializer):
    group_id = serializer.IntegerField()
    group_name = serializer.CharField(max_length = 20)
    join_date = serializer.DateTimeField()

CustomModels.py

imports...

    class AllDataModel():
        group_id = ""
        group_name = ""
        join_date = ""

BusinessLogic.py

imports ....
class getdata(memberid):
    alldataDict = {}
    dto = []
    Member = models.Members.objects.get(member_id=memberid) #or use filter for Name
    alldataDict["MemberId"] = Member.member_id
    alldataDict["MemberName"] = Member.member_name
    Groups = models.Group.objects.filter(fk_member_id=Member)
    for item in Groups:
        Custommodel = CustomModels.AllDataModel()
        Custommodel.group_id = item.group_id
        Custommodel.group_name = item.group_name
        Membership = models.Membership.objects.get(fk_group_id=item.group_id)
        Custommodel.join_date = Membership.join_date
        dto.append(Custommodel)
    serializer = AllSerializer(dto,many=True)
    alldataDict.update(serializer.data)
    return alldataDict

Về mặt kỹ thuật, bạn sẽ phải chuyển Yêu cầu tới DataAccessLayer, yêu cầu này sẽ trả về Đối tượng được lọc từ Lớp truy cập dữ liệu nhưng vì tôi phải Trả lời câu hỏi trong Trình xử lý nhanh nên tôi đã điều chỉnh Mã trong Lớp logic nghiệp vụ!


1
Đây là Phương pháp tiếp cận được tùy chỉnh đầy đủ mà tôi sử dụng cho hầu hết các phát triển API Rest của mình vì tôi không thực sự thích làm việc với Bounds mặc dù Django Rest Framework khá linh hoạt!
Syed Faizan

2
Điều này có thể được thiết kế quá mức, thậm chí nó không sử dụng DRF.
michauwilliam
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.