optimistiks
optimistiks

Reputation: 491

Django Rest Framework, hyperlinking a nested relationship

I've got two models: User and Ticket. Ticket has one User, User has many Tickets

I've accomplished that when i go to url /users/1/tickets, i'm getting the list of user's tickets.

I want to use hyperlinked relations, and here is what i see in my User model representation:

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

But I want it to be like

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

Is there a way to do that with DRF?

The url:

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

The view:

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 tried to play with tickets field definition, changing type, view_name, but with no effect):

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

Upvotes: 8

Views: 6176

Answers (2)

Mario
Mario

Reputation: 2639

For the record, here is an example of the full solution based on Joe Holloway's answer:

from rest_framework.reverse import reverse

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__'

Upvotes: 4

Joe Holloway
Joe Holloway

Reputation: 28948

You can use a SerializerMethodField to customize it. Something like this:

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

I hard-wired the URL in there for brevity, but you can do a reverse lookup just as well. This basically just tells it to call the get_tickets method instead of the default behavior in the superclass.

Upvotes: 18

Related Questions