trubliphone
trubliphone

Reputation: 4504

Using HyperlinkedField for serializer in Django Rest Framework

All,

I am having trouble making one of my model's relational fields show up as a hyperlink in Django Rest Framework. (I am working off of the examples provided at http://www.django-rest-framework.org/api-guide/relations/.) Here is my code:

models.py:

class Album(models.Model):
    album_name = models.CharField(max_length=100)
    artist = models.CharField(max_length=100)

class Track(models.Model):
    album = models.ForeignKey(Album, related_name='tracks')
    order = models.IntegerField()
    title = models.CharField(max_length=100)
    duration = models.IntegerField()

    class Meta:
        unique_together = ('album', 'order')
        ordering = ['order']

    def __unicode__(self):
        return '%d: %s' % (self.order, self.title)

serializers.py:

class AlbumSerializer(serializers.ModelSerializer):
    tracks = serializers.StringRelatedField(many=True)

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

class TrackSerializer(serializers.ModelSerializer):
    # THIS WORKS...
    # album = serializers.SlugRelatedField(slug_field="album_name", read_only=True)
    # THIS DOES NOT WORK...
    album = serializers.HyperlinkedRelatedField(view_name="album-detail", read_only=True)

    class Meta:
        model = Track
        fields = ('album', 'order', 'title', 'duration')

views.py:

@api_view(('GET',))
def api_root(request, format=None):
    return Response({
        'albums': reverse("album-list", request=request, format=format),
        'tracks': reverse("track-list", request=request, format=format),
    })

class AlbumList(APIView):

    def get(self, request, format=None):
        albums = Album.objects.all()
        serializer = AlbumSerializer(albums, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        album = AlbumSerializer(data=request.data)
        if album.is_valid():
            album.save()
            return Response(album.data, status=status.HTTP_201_CREATED)
        else:
            return Response(album.errors, status=status.HTTP_400_BAD_REQUEST)

class AlbumDetail(APIView):

    def get_object(self, pk):
        try:
            return Album.objects.get(pk=pk)
        except Album.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        album = self.get_object(pk)
        serializer = AlbumSerializer(album)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        album = self.get_object(pk)
        serializer = AlbumSerializer(album, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        album = self.get_object(pk)
        album.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

class TrackList(APIView):
    def get(self, request, format=None):
        tracks = Track.objects.all()
        serializer = TrackSerializer(tracks, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        track = TrackSerializer(data=request.data)
        if track.is_valid():
            track.save()
            return Response(track.data, status=status.HTTP_201_CREATED)
        else:
            return Response(track.errors, status=status.HTTP_400_BAD_REQUEST)

class TrackDetail(APIView):
    def get_object(self, pk):
        try:
            return Track.objects.get(pk=pk)
        except Track.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        track = self.get_object(pk)
        serializer = TrackSerializer(track)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        track = self.get_object(pk)
        serializer = TrackSerializer(track, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        track = self.get_object(pk)
        track.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

urls.py:

urlpatterns = patterns('',
    url(r'^api/$', api_root),
    url(r'^api/albums/$', AlbumList.as_view(), name="album-list"),
    url(r'^api/albums/(?P<pk>[0-9]+)/$', AlbumDetail.as_view(), name="album-detail"),
    url(r'^api/tracks/$', TrackList.as_view(), name="track-list"),
    url(r'^api/tracks/(?P<pk>[0-9]+)/$', TrackDetail.as_view(), name="track-detail"),

)

urlpatterns = format_suffix_patterns(urlpatterns)

When I use the SlugRelatedField in the TrackSerializer, everything works as expected. But when I use the HyperlinkedRelatedField, I get the following error:

AssertionError at /api/tracks/

HyperlinkedRelatedField requires the request in the serializer context. Add context={'request': request} when instantiating the serializer.

Any thoughts?

Upvotes: 2

Views: 5021

Answers (1)

jgadelange
jgadelange

Reputation: 2572

As @zymud said, you should change the serializer to serializer = AlbumSerializer(album, context={'request': request}) in the AlbumList and AlbumDetail views

Upvotes: 8

Related Questions