
Django
Django REST Framework 嵌套资源键“id”无法访问
在使用Django REST Framework进行API开发时,我们经常会遇到需要嵌套资源的情况。嵌套资源可以帮助我们更好地组织和展示数据。然而,有时我们可能会遇到一个问题,就是无法通过嵌套资源的键“id”来访问数据。本文将介绍这个问题的原因,并提供解决方案。问题描述在Django REST Framework中,我们可以通过定义Serializer来控制API的数据输出。当我们需要嵌套资源时,可以使用Serializer的嵌套字段来实现。例如,我们有两个模型:Author(作者)和Book(书籍),它们之间是一对多的关系。我们可以定义如下的Serializer:Pythonclass 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值。下面是一个示例代码:Pythonfrom rest_framework.routers import DefaultRouter, Routeclass 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然后,在我们的视图集中使用这个新的解析器类:Pythonclass 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来访问数据的功能。以上就是解决这个问题的一个示例代码,希望能对你有所帮助。
Copyright © 2025 IZhiDa.com All Rights Reserved.
知答 版权所有 粤ICP备2023042255号