2013-06-23 24 views
67

Ho una domanda su come trattare i modelli m2m/through e la loro presentazione nel framework django rest. Facciamo un esempio classico:Includi un intermediario (tramite il modello) nelle risposte in 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 

Quando geting un'istanza di Stati, Ricevo tutti i campi del membro e anche i suoi gruppi, tuttavia ottengo solo i dettagli dei gruppi, senza dettagli aggiuntivi t cappello proviene dal modello Membership.

In altre parole ho aspetto per ricevere:

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

Annotare il join_date.

Ho provato oh così tante soluzioni, tra cui ovviamente Django Rest-Framework official page about it e nessuno sembra dare una risposta adeguata a questo proposito - cosa devo fare per includere questi campi aggiuntivi? L'ho trovato più diretto con django-tastypie ma ho avuto altri problemi e preferisco il framework di riposo.

+0

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

+6

Questo è per torta gustosa, sto lavorando con Django Rest Framework. – mllm

risposta

88

Come su .....

Sul MemberSerializer, definire un campo su di esso come:

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

e poi sul vostro serializzatore iscrizione è possibile creare questa:

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

Questo ha l'effetto generale di creare un valore serializzato, gruppi, che ha come origine l'appartenenza desiderata, e quindi utilizza un serializzatore personalizzato per estrarre i bit che si desidera visualizzare.

EDIT: come commentato da @bryanph, serializers.field stato rinominato in serializers.ReadOnlyField in DRF 3.0, quindi questo dovrebbe leggere:

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

per eventuali implementazioni moderne

+1

fyi, ho provato molte varianti di questo e non riesco a farlo funzionare. Questo non è nei documenti ufficiali? Dove è definito membership_set? – clay

+2

'membership_set' è il nome correlato predefinito per Membro -> Membership – dustinfarris

+0

La parte del trucco per me è stata la scoperta del nome" membership_set ". Avevo un modello passante senza un nome "correlato" esplicito, quindi ho dovuto indovinare il nome di esso, leggendo i documenti in [Django Many to Many] (https://docs.djangoproject.com/en/1.9/topics/db/examples/many_to_many /). – miceno

3

stavo affrontando questo problema e la mia soluzione (utilizzando DRF 3.6) è stato quello di utilizzare SerializerMethodField sull'oggetto e interrogare esplicitamente il tavolo iscrizione in questo modo:

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] 

Ciò ri trasforma una lista di dict per la chiave di gruppo in cui ogni dict è serializzato da MembershipSerializer. Per renderlo scrivibile, è possibile definire il proprio metodo di creazione/aggiornamento all'interno di MemberSerializer in cui si esegue l'iterazione sui dati di input e si creano o aggiornano in modo esplicito le istanze del modello di appartenenza.

Problemi correlati