django.core.exceptions.ImproperlyConfigured:无法使用视图名称解析超链接关系的URL" user-detail"

时间:2016-10-16 17:26:58

标签: python django rest hyperlink django-rest-framework

TL; DR:我收到此错误并且不知道原因:

  

django.core.exceptions.ImproperlyConfigured:无法使用视图名称" user-detail"解析超链接关系的URL。您可能未能在API中包含相关模型,或者未正确配置' lookup_field'该字段的属性。

我正在浏览django-rest-framework tutorial,目前处于基于功能的视图(FBV)切换到class,mixin和基于泛型的视图(分别为CBV,MBV,GBV)的点。切换到GBV后,当我去测试我的API时,收到了此错误AssertionError: Expected view SnippetDetail to be called with a URL keyword argument named "pk". Fix your URL conf, or set the '.lookup_field' attribute on the view correctly.。我做了一些研究,发现lookup_field needs to be set to the in the urlpatterns。目前,我的urls.py看起来像这样:

from django.conf.urls import url, include
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views

# API endpoints
urlpatterns = format_suffix_patterns([
    url(r'^$', views.api_root),
    url(r'^snippets/$',
        views.SnippetList.as_view(),
        name='snippet-list'),
    url(r'^snippets/(?P<id>[0-9]+)/$',
        views.SnippetDetail.as_view(),
        name='snippet-detail'),
    url(r'^users/$',
        views.UserList.as_view(),
        name='user-list'),
    url(r'^users/(?P<id>[0-9]+)/$',
        views.UserDetail.as_view(),
        name='user-detail')
])

# Login and logout views for the browsable API
urlpatterns += [
    url(r'^auth/', include('rest_framework.urls',
                           namespace='rest_framework')),
]

和我的views.py看起来像这样:

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer, UserSerializer
from snippets.permissions import IsOwnerOrReadOnly

from rest_framework import generics
from rest_framework import permissions
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse

from django.contrib.auth.models import User


@api_view(['GET'])
def api_root(request, format=None):
    return Response({
        'users': reverse('user-list', request=request, format=format),
        'snippets': reverse('snippet-list', request=request, format=format)
    })


class UserList(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer


class UserDetail(generics.RetrieveAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer


class SnippetList(generics.ListCreateAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly, )

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)


class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly, )

当我在UserDetail和SnippetDetail中添加lookup_field = 'id'时,异常会自行解决。 (好极了!)。但是,当我访问时http://127.0.0.1/users/1/ ImproperlyConfigured: Could not resolve URL for hyperlinked relationship using view name "user-detail". You may have failed to include the related model in your API, or incorrectly configured the 'lookup_field' attribute on this field.被抛出。但是,当我检查控制台时,还有第二个例外:

  

django.urls.exceptions.NoReverseMatch:反向&#39;用户详细信息&#39;同   论证&#39;()&#39;和关键字参数&#39; {&#39; pk&#39;:1}&#39;未找到。 2   模式尝试:[&#39;用户/(?P [0-9] +)\。(?P [a-z0-9] +)/?$&#39;,   &#39;用户/ / $&#39(P [0-9] +);]

     

在处理上述异常期间,发生了另一个异常:

     

django.core.exceptions.ImproperlyConfigured:无法解析网址   使用视图名称&#34; user-detail&#34;的超链接关系。你可能有   未能在您的API中包含相关模型,或者说错误   配置了&#39; lookup_field&#39;该字段的属性。

我觉得有趣的是第一个例外的kwargs是{'pk': 1},而不是{'id':1}。在聊天的一些帮助之后,有人给我指了this条信息:

  

请注意,使用超链接API时,如果需要使用自定义值,则需要确保API视图和序列化程序类都设置了查找字段。

这在User序列化程序扩展HyperlinkedModelSerializer

时非常有用
from rest_framework import serializers

from django.contrib.auth.models import User

from snippets.models import Snippet

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')

User模型和序列化程序与Snippet具有反向关系。现在,当我将lookup_field='id'添加到UserSerializersnippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail', read_only=True, lookup_field='id'))的片段属性时,就像它要求我这样做here一样,错误是持久的。

我做错了什么?我该怎么做才能解决这个问题?它与lookup_id没有任何关系吗?

我知道我可以在我的网址中用<id>替换<pk>,但我想了解为什么这种情况发生。

2 个答案:

答案 0 :(得分:0)

我最终通过在Django shell / python交互式控制台中打印序列化程序来修复我的第二个异常。我得到的结果是:

>>> from snippets.serializers import UserSerializer
>>> print(UserSerializer())
UserSerializer():
    url = HyperlinkedIdentityField(view_name='user-detail')
    id = IntegerField(label='ID', read_only=True)
    username = CharField(help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, validators=[<django.contrib.auth.validators.UnicodeUsernameValidator object>, <UniqueValidator(queryset=User.objects.all())>])
    snippets = HyperlinkedRelatedField(lookup_field='id', many=True, read_only=True, view_name='snippet-detail')

事实证明,要在urlspatterns中将<pk>更改为<id>,您需要在url = HyperlinkedIdentityField(view_name='user-detail', lookup_field='id')类中添加UserSerializer

答案 1 :(得分:0)

我遇到了同样的问题,我发现,HyperlinkedIdentityField想要在您的网址中插入一些占位符。但是我使用了不需要任何占位符的URL。确切地说ListCreateAPIView

url(
    r'^users/$',                  #<-- takes no params
    views.UserListView.as_view(), #<-- just prints a list 
    name="user-list"              #<-- HyperlinkedIdentityField pointing 
),                                #     here complained bitterly.