Django Rest Framework의 응답에 중개자 (모델을 통해) 포함


110

m2m / 모델 및 django rest 프레임 워크의 프레젠테이션을 통해 처리하는 것에 대한 질문이 있습니다. 고전적인 예를 들어 보겠습니다.

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

Member 인스턴스를 가져올 때 모든 구성원 필드와 그룹을 성공적으로 수신합니다. 그러나 Membership 모델에서 제공하는 추가 세부 정보없이 그룹 세부 정보 만 가져옵니다.

즉, 다음 을받을 것으로 예상 합니다.

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

join_date를 참고하십시오 .

물론 Django Rest-Framework 공식 페이지를 포함하여 너무 많은 솔루션을 시도했지만 아무도 그것에 대한 적절한 대답을 제공하지 않는 것 같습니다. 이러한 추가 필드를 포함하려면 어떻게해야합니까? 나는 django-tastypie로 더 간단하다는 것을 알았지 만 다른 문제가 있었고 나머지 프레임 워크를 선호했습니다.


겠습니까 eugene-yeo.me/2012/12/4/... 도움을?
karthikr

8
이것은 맛있는 파이를위한 것이며 Django Rest Framework로 작업하고 있습니다.
mllm

답변:


139

어때 .....

MemberSerializer에서 다음과 같이 필드를 정의하십시오.

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

그런 다음 멤버십 직렬 변환기에서 다음을 만들 수 있습니다.

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

이는 원하는 멤버 자격을 소스로 갖는 직렬화 된 값, 그룹을 생성하는 전체적인 효과가 있으며 사용자 지정 직렬 변환기를 사용하여 표시하려는 비트를 가져옵니다.

편집 : @bryanph가 주석으로 DRF 3.0에서 serializers.field이름이 변경 되었으므로 다음과 같이 serializers.ReadOnlyField읽어야합니다.

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

현대적인 구현을 위해


2
참고로, 나는 이것의 많은 변형을 시도했지만 이것을 작동시킬 수 없습니다. 이것은 공식 문서에 없습니까? member_set은 어디에 정의되어 있습니까?
점토

3
membership_set회원의 기본과 관련된 이름은 -> 회원
dustinfarris

나를위한 트릭 부분은 "membership_set"이름을 발견하는 것이 었습니다. 나는 명시적인 "관련"이름이없는 관통 모델을 가지고 있었기 때문에 Django Many to Many 에서 문서를 읽고 그 이름을 추측해야했습니다 .
miceno

힌트 주셔서 감사합니다. 그러나이 경우 DRF는 Member 클래스가 이미 그룹이라는 m2m 필드를 정의 하고이 솔루션은 모델을 통해 역 관계를 가리 키도록 강제하여 직렬화 기의 필드를 재정의하는 것처럼 보이기 때문에 다소 직관적이지 않습니다. 나는 DRF 구현 세부 사항에별로 관심이 없지만 모델 내부 검사를 사용하면 자동으로 전달 될 수 있습니다. 생각할 음식이 몇 가지 있습니다. :)
gru

최신 버전의 DRF에서 작동하는지 여부에 대해 업데이트 해 주시겠습니까? 아니면 적어도 어떤 버전을 사용하고 있었는지 알려주세요? 필드를 통해 모델을 반환하도록 DRF를 만들 수 없습니다. 항상 원래 관계로 끝납니다 (멤버쉽 대신 항상 그룹을 반환합니다).
Andrey Cizov

18

이 문제에 직면했고 내 솔루션 (DRF 3.6 사용)은 개체에 SerializerMethodField를 사용하고 다음과 같이 Membership 테이블을 명시 적으로 쿼리하는 것입니다.

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]

그러면 MembershipSerializer에서 각 사전이 직렬화되는 그룹 키에 대한 사전 목록이 반환됩니다. 쓰기 가능하게하려면 입력 데이터를 반복하고 Membership 모델 인스턴스를 명시 적으로 생성 또는 업데이트하는 MemberSerializer 내에서 고유 한 생성 / 업데이트 메서드를 정의 할 수 있습니다.


-4

참고 : 소프트웨어 엔지니어로서 저는 아키텍처를 사용하는 것을 좋아하고 개발을위한 계층화 접근 방식을 깊이 연구 해 왔으므로 계층에 대한 응답으로 대답 할 것입니다.

문제를 이해 했으므로 여기에 솔루션이 있습니다. models.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

기술적으로는 데이터 액세스 레이어에서 필터링 된 개체를 반환하는 DataAccessLayer에 요청을 전달해야하지만 빠른 방식으로 질문에 답해야하므로 비즈니스 로직 레이어에서 코드를 조정했습니다!


1
이것은 Django Rest Framework가 매우 유연하더라도 Bounds 작업의 팬이 아니기 때문에 대부분의 Rest API 개발에 사용하는 완전 맞춤형 접근 방식입니다!
Syed Faizan

2
이것은 너무 과도하게 설계되었으며 DRF를 사용하지도 않습니다.
michauwilliam
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.