在 Django Rest Framework 中使用 HyperlinkedField 作为序列化程序

Using HyperlinkedField for serializer in Django Rest Framework

全部,

我无法让我的模型的一个关系字段在 Django Rest Framework 中显示为超链接。 (我正在处理 http://www.django-rest-framework.org/api-guide/relations/ 中提供的示例。)这是我的代码:

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)

当我在 TrackSerializer 中使用 SlugRelatedField 时,一切都按预期工作。但是当我使用 HyperlinkedRelatedField 时,出现以下错误:

AssertionError at /api/tracks/

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

有什么想法吗?

正如@zymud 所说,您应该在 AlbumListAlbumDetail 视图

中将序列化器更改为 serializer = AlbumSerializer(album, context={'request': request})