Я работаю с учебным пособием Django Rest Framework, и на самый последний шаг я сталкиваюсь с ошибкой:
Exception Type: ImproperlyConfigured.
Exception Value:
Could not resolve URL for hyperlinked relationship using view name "snippet-detail". You may have failed to include the related model in your API, or incorrectly configured the lookup_field attribute on this field.
При попытке просмотреть либо /settings/, либо /users/ (посещение любых пользовательских страниц приводит к тому же исключению, но с «детали пользователя» вместо «детали фрагмента»), а также любые их конкретные индексы и т. д. Все это работает это root и логин.
Весь мой код до сих пор работал нормально, и я очень смущен тем, почему копирование из учебника приведет к таким катастрофическим результатам.
При сравнении моих файлов фрагментов с файлами, доступными на репозиторий учебника, я не смог найти какой-либо существенной разницы (все, что я нашел, это несоответствия в пробелах). При этом, вот код, который я использую.
фрагменты/views.py:
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer, UserSerializer
from rest_framework import generics, permissions
from django.contrib.auth.models import User
from snippets.permissions import IsOwnerOrReadOnly
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse
from rest_framework import renderers
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import permissions
from rest_framework import viewsets
class UserViewSet(viewsets.ReadOnlyModelViewSet):
"""
This viewset automatically provides `list` and `retrieve` actions.
"""
queryset = User.objects.all()
serializer_class = UserSerializer
class SnippetViewSet(viewsets.ModelViewSet):
"""
This viewset automatically provides `list`, `create`, `retrieve`,
`update` and `destroy` actions.
Additionally we also provide an extra `highlight` action.
"""
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOnly]
@action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])
def highlight(self, request, *args, **kwargs):
snippet = self.get_object()
return Response(snippet.highlighted)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
фрагменты/urls.py:
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from snippets import views
# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet,basename = "snippets")
router.register(r'users', views.UserViewSet,basename = "users")
# The API URLs are now determined automatically by the router.
urlpatterns = [
path('', include(router.urls)),
]
фрагменты/serializers.py:
from django.contrib.auth.models import User
from rest_framework import serializers
from snippets.models import Snippet
class SnippetSerializer(serializers.HyperlinkedModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
highlight = serializers.HyperlinkedIdentityField(
view_name='snippet-highlight', format='html')
class Meta:
model = Snippet
fields = ('url', 'id', 'highlight', 'owner', 'title', 'code',
'linenos', 'language', 'style')
class UserSerializer(serializers.HyperlinkedModelSerializer):
snippets = serializers.HyperlinkedRelatedField(
many=True, view_name='snippet-detail', read_only=True)
class Meta:
model = User
fields = ('url', 'id', 'username', 'snippets')
учебник/urls.py:
"""tutorial URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('snippets.urls')),
]
urlpatterns += [
path('api-auth/', include('rest_framework.urls')),
]
@IainShelvington Большое спасибо! Сильно расстроился. Чтобы прояснить для тех, кто изначально был сбит с толку, как и я, проблема заключалась в том, что базовые имена были основаны на множественном числе (создание маршрутов user-detail и snippets-detail, а не user-detail и snippet-detail)
Маршрутизатору передавались неправильные базовые имена (множественное число от сниппета и пользователя, а не единственное). Спасибо @IainShelvington за ответ в комментариях!
Чтобы уточнить:
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from snippets import views
# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet,basename = "snippets")
router.register(r'users', views.UserViewSet,basename = "users")
# The API URLs are now determined automatically by the router.
urlpatterns = [
path('', include(router.urls)),
]
должны были быть
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from snippets import views
# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet,basename = "snippet")
router.register(r'users', views.UserViewSet,basename = "user")
# The API URLs are now determined automatically by the router.
urlpatterns = [
path('', include(router.urls)),
]
Ваш ответ может быть улучшен с помощью дополнительной вспомогательной информации. Пожалуйста, редактировать добавьте дополнительную информацию, например цитаты или документацию, чтобы другие могли подтвердить правильность вашего ответа. Дополнительную информацию о том, как писать хорошие ответы, можно найти в справочном центре.
Вы передали
basename
для обоих наборов представлений в вашем маршрутизаторе, базовое имя будет использоваться для генерации имен представлений:snippets-detail
иusers-detail