2013-11-04 5 views
7

Ich habe zwei Modelle: Benutzer und Ticket. Ticket hat ein Benutzer, Benutzer viele TicketsDjango Rest Framework, Hyperlinking eine verschachtelte Beziehung

Ich habe hat erreicht, dass, wenn ich gehen/users/1/Tickets url, ich bin die Liste der Benutzer-Tickets zu bekommen.

Ich möchte verlinkte Beziehungen verwenden, und hier ist das, was ich in meinem User-Modell Darstellung siehe:

"tickets": [ 
    "http://127.0.0.1:8000/tickets/5/", 
    "http://127.0.0.1:8000/tickets/6/" 
] 

Aber ich will es wie

"tickets": "http://127.0.0.1:8000/users/1/tickets" 

Gibt es eine Möglichkeit sein, zu tun das mit DRF?

Die url:

url(r'^users/(?P<user_pk>\d+)/tickets/$', 
    views.TicketsByUserList.as_view(), 
    name='myuser-tickets'), 

Aussicht:

class TicketsByUserList(generics.ListAPIView): 
    model = Ticket 
    serializer_class = TicketSerializer 

    def get_queryset(self): 
     user_pk = self.kwargs.get('user_pk', None) 
     if user_pk is not None: 
      return Ticket.objects.filter(user=user_pk) 
     return [] 

User-Serializer (i versucht, mit Tickets Felddefinition zu spielen, Typ, view_name verändern, aber ohne Wirkung):

class UserSerializer(serializers.HyperlinkedModelSerializer): 
    tickets = serializers.HyperlinkedRelatedField(many=True, view_name='ticket-detail') 

    class Meta: 
     model = MyUser 
     fields = ('id', 'nickname', 'email', 'tickets') 

Ticket-Serializer:

class TicketSerializer(serializers.HyperlinkedModelSerializer): 
    user = serializers.HyperlinkedRelatedField(view_name='myuser-detail') 
    liked = serializers.Field(source='liked') 

    class Meta: 
     model = Ticket 
     fields = ('id', 'user', 'word', 'transcription', 'translation', 'liked', 'created', 'updated') 

Antwort

15

Sie können eine SerializerMethodField verwenden, um sie anzupassen. Etwas wie folgt aus:

class UserSerializer(serializers.HyperlinkedModelSerializer): 
    tickets = serializers.SerializerMethodField('get_tickets') 

    def get_tickets(self, obj): 
     return "http://127.0.0.1:8000/users/%d/tickets" % obj.id 

    class Meta: 
     model = MyUser 
     fields = ('id', 'nickname', 'email', 'tickets') 

ich die URL dort der Kürze halber festverdrahtet, aber man kann genauso gut ein Reverse-Lookup tun. Dies bedeutet im Grunde nur, dass es die get_tickets Methode anstelle des Standardverhaltens in der Oberklasse aufruft.

+0

Bei dem Versuch, Ihre Lösung zu implementieren, wurde mir klar, dass ich irgendwie Objekt die Anfrage an den Serializer passieren, um es in umgekehrte Funktion zu übergeben, um eine absolute URL zu erhalten. Ich löste es, indem ich ein Anforderungsobjekt von der Ansicht "Dispatch" -Methode an das Feld in meinem Serializer übergab. Aber ich habe das Gefühl, dass das Überschreiben einer Versandmethode jedes Mal, wenn ich ein Anfrageobjekt in meinem Serialisierer haben möchte, keine gute Idee ist. Was ist der beste Weg, um eine Anfrage im Serializer zu bekommen? – optimistiks

+1

Es gibt eine Möglichkeit, Ihrem Serializer zusätzlichen Kontext zu geben (http://django-rest-framework.org/api-guide/serializers.html#inclusive-extra-context). Die Dokumentation zeigt Ihre genaue Situation als Beispiel für den Anwendungsfall. –

+2

In 'get_tickets' Methode können Sie das Anfrageobjekt mit' request = self.context.get ('request') 'abrufen, dann rufen Sie' reverse' wie gewohnt auf. – Cartucho

0

Für die Aufzeichnung, hier ist ein Beispiel für den vollständigen Lösung auf Basis von Joe Holloway Antwort:

class WorkProjectSerializer(serializers.CustomSerializer): 
    issues = drf_serializers.SerializerMethodField() 

    def get_issues(self, obj): 
     request = self.context.get('request') 
     return request.build_absolute_uri(reverse('project-issue-list', kwargs={'project_id': obj.id})) 

    class Meta: 
     model = WorkProject 
     fields = '__all__'