Django REST Framework 嵌套资源键“id”无法访问

django

1个回答

写回答

就爱追剧

2025-09-07 04:30

+ 关注

Django
Django

Django REST Framework 嵌套资源键“id”无法访问

在使用Django REST Framework进行API开发时,我们经常会遇到需要嵌套资源的情况。嵌套资源可以帮助我们更好地组织和展示数据。然而,有时我们可能会遇到一个问题,就是无法通过嵌套资源的键“id”来访问数据。本文将介绍这个问题的原因,并提供解决方案。

问题描述

Django REST Framework中,我们可以通过定义Serializer来控制API的数据输出。当我们需要嵌套资源时,可以使用Serializer的嵌套字段来实现。例如,我们有两个模型:Author(作者)和Book(书籍),它们之间是一对多的关系。我们可以定义如下的Serializer:

Python

class BookSerializer(serializers.ModelSerializer):

class Meta:

model = Book

fields = ('id', 'title', 'author')

class AuthorSerializer(serializers.ModelSerializer):

books = BookSerializer(many=True)

class Meta:

model = Author

fields = ('id', 'name', 'books')

这样,当我们通过AuthorSerializer序列化一个Author对象时,会自动嵌套序列化该Author所写的所有书籍。然而,问题出现在我们想通过书籍的id来访问某一本书的详细信息时。例如,我们想通过/api/authors/1/books/2来获取id为2的书籍的信息。但实际上,这样的请求会返回404错误,无法找到该资源。

问题原因

问题的原因在于Django REST Framework默认情况下,不会将嵌套字段的键名中的“id”解析为实际的id值。这是为了避免与主资源的id冲突。因此,我们需要手动修改默认的行为,才能实现通过嵌套资源的id来访问数据。

解决方案

要解决这个问题,我们可以通过重写Django REST Framework的路由解析器来实现。首先,我们需要创建一个新的解析器类,继承自默认的路由解析器。然后,我们重写get_lookup_value方法,在该方法中将嵌套字段的键名中的“id”解析为实际的id值。下面是一个示例代码:

Python

from rest_framework.routers import DefaultRouter, Route

class NestedResourcesRouter(DefaultRouter):

routes = [

Route(

url=r'^{prefix}/{lookup}/{nested_field}/{nested_lookup}$',

mapping={

'get': 'retrieve_nested',

'put': 'update_nested',

'patch': 'partial_update_nested',

'delete': 'destroy_nested'

},

name='{basename}-nested',

detAIl=True,

initkwargs={}

),

Route(

url=r'^{prefix}/{lookup}/{nested_field}$',

mapping={

'get': 'list_nested',

'post': 'create_nested'

},

name='{basename}-nested-list',

detAIl=True,

initkwargs={}

),

]

def get_lookup_value(self, request, view):

lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field

lookup_value = view.kwargs[lookup_url_kwarg]

lookup_field = view.lookup_field

if lookup_field == 'pk':

return int(lookup_value)

return lookup_value

然后,在我们的视图集中使用这个新的解析器类:

Python

class AuthorViewSet(viewsets.ModelViewSet):

queryset = Author.objects.all()

serializer_class = AuthorSerializer

lookup_field = 'id'

lookup_value_RegEx = '[^/]+'

lookup_url_kwarg = 'author_id'

router = NestedResourcesRouter()

@action(detAIl=True, methods=['get'])

def books(self, request, author_id=None):

author = self.get_object()

books = author.books.all()

serializer = BookSerializer(books, many=True)

return Response(serializer.data)

@action(detAIl=True, methods=['get'])

def books_detAIl(self, request, author_id=None, book_id=None):

author = self.get_object()

book = author.books.get(id=book_id)

serializer = BookSerializer(book)

return Response(serializer.data)

现在,我们就可以通过/api/authors/1/books/2来获取id为2的书籍的详细信息了。

在使用Django REST Framework开发API时,嵌套资源是非常常见的需求。然而,由于默认的路由解析器不会将嵌套字段的键名中的“id”解析为实际的id值,我们无法通过嵌套资源的id来访问数据。通过重写路由解析器,我们可以解决这个问题,并实现通过嵌套资源的id来访问数据的功能。以上就是解决这个问题的一个示例代码,希望能对你有所帮助。

举报有用(4分享收藏

Copyright © 2025 IZhiDa.com All Rights Reserved.

知答 版权所有 粤ICP备2023042255号