2013-06-23 4 views
67

Mam pytanie dotyczące radzenia sobie z modelami m2m/through i ich prezentacją w strukturze django rest. Weźmy klasyczny przykład:Dołącz pośrednika (poprzez model) w odpowiedziach w Django Rest Framework

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 

Kiedy czuło wystąpienie posła, Pomyślnie odbieram wszystkie pola uczestnika, a także jego grupy - jednak dostaję tylko szczegóły grupy, bez dodatkowych szczegółów kapelusz pochodzi z modelu członkostwa.

Innymi słowy Spodziewam otrzymywać:

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

Zanotuj join_date.

Próbowałem wielu rozwiązań, w tym oczywiście Django Rest-Framework official page about it i nikt nie wydaje właściwej odpowiedzi na to pytanie - co muszę zrobić, aby uwzględnić te dodatkowe pola? Znalazłem to bardziej prosto z django-tastypie, ale miałem inne problemy i wolę rest-framework.

+0

Czy http://eugene-yeo.me/2012/12/4/django-tastypie-manytomany-through-part-2/ help? – karthikr

+6

To jest za smaczne ciasto, pracuję z Django Rest Framework. – mllm

Odpowiedz

88

Jak o .....

Na MemberSerializer, zdefiniować pole na nim podoba:

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

a następnie członkostwa serializatora można tworzyć w ten sposób:

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

To daje ogólny efekt tworzenia wartości szeregowej, grup, której źródłem jest żądane członkostwo, a następnie używa niestandardowego serializera do wyciągnięcia bitów, które chcesz wyświetlić.

EDIT: jak komentował @bryanph, serializers.field został przemianowany na serializers.ReadOnlyField w DRF 3.0, więc ten powinien brzmieć:

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

wszelkich nowoczesnych wdrożeń

+1

fyi, próbowałem wielu wariantów tego i nie mogę tego uruchomić. To nie jest w oficjalnych dokumentach? Gdzie zdefiniowany jest zestaw członkostwa? – clay

+2

'member_set' to domyślna nazwa powiązana dla Członka -> Członkostwo – dustinfarris

+0

Zaskoczeniem dla mnie było odkrycie nazwy" membership_set ". Miałem przelotowy model bez wyraźnej "powiązanej" nazwy, więc musiałem odgadnąć jego nazwę, czytając dokumenty w [Django Many to Many] (https://docs.djangoproject.com/en/1.9/topics/db/examples/many_to_many /). – miceno

3

byłem w obliczu tego problemu i moje rozwiązanie (stosując DRF 3.6) było użycie SerializerMethodField na obiekcie i wyraźnie kwerendy tabeli Membership tak:

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] 

to ponownie włącz listę dykt dla klucza grup, w którym każdy dict jest serializowany z MembershipSerializer. Aby umożliwić zapis, można zdefiniować własną metodę tworzenia/aktualizacji w programie MemberSerializer, w której można wykonać iterację danych wejściowych i jawnie utworzyć lub zaktualizować instancje modelu członkostwa.