Django Rest Framework - 无法使用视图名称“user-detail”解析超链接关系的URL

时间:2013-12-12 17:49:04

标签: python django django-rest-framework

我正在Django Rest Framework中构建一个项目,用户可以登录查看他们的酒窖。 我的ModelViewSets工作得很好,突然间我得到了这个令人沮丧的错误:

  

无法使用视图名称“user-detail”解析超链接关系的URL。您可能未能在API中包含相关模型,或者在此字段上错误地配置了lookup_field属性。

追溯显示:

    [12/Dec/2013 18:35:29] "GET /bottles/ HTTP/1.1" 500 76677
Internal Server Error: /bottles/
Traceback (most recent call last):
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/django/core/handlers/base.py", line 114, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/viewsets.py", line 78, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 57, in wrapped_view
    return view_func(*args, **kwargs)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/views.py", line 399, in dispatch
    response = self.handle_exception(exc)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/views.py", line 396, in dispatch
    response = handler(request, *args, **kwargs)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/mixins.py", line 96, in list
    return Response(serializer.data)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/serializers.py", line 535, in data
    self._data = [self.to_native(item) for item in obj]
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/serializers.py", line 325, in to_native
    value = field.field_to_native(obj, field_name)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/relations.py", line 153, in field_to_native
    return self.to_native(value)
  File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/relations.py", line 452, in to_native
    raise Exception(msg % view_name)
Exception: 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.

我有自定义电子邮件用户模型,models.py中的瓶子模型是:

class Bottle(models.Model):    
      wine = models.ForeignKey(Wine, null=False)
      user = models.ForeignKey(User, null=False, related_name='bottles')

我的序列化器:

class BottleSerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = Bottle
        fields = ('url', 'wine', 'user')

class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = ('email', 'first_name', 'last_name', 'password', 'is_superuser')

我的观点:

class BottleViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows bottles to be viewed or edited.
    """
    queryset = Bottle.objects.all()
    serializer_class = BottleSerializer

class UserViewSet(ListCreateAPIView):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer

最后是网址:

router = routers.DefaultRouter()
router.register(r'bottles', views.BottleViewSet, base_name='bottles')

urlpatterns = patterns('',
    url(r'^', include(router.urls)),
    # ...

我没有用户详细信息视图,但我没有看到此问题的来源。有什么想法吗?

由于

19 个答案:

答案 0 :(得分:78)

因为HyperlinkedModelSerializer您的序列化程序正在尝试解析User上相关Bottle的网址。 由于您没有用户详细信息视图,因此无法执行此操作。因此例外。

  1. 不只是在路由器上注册UserViewSet来解决您的问题吗?
  2. 您可以在BottleSerializer上定义用户字段,以明确使用UserSerializer,而不是尝试解析该网址。请参阅serializer docs on dealing with nested objects for that

答案 1 :(得分:47)

我也遇到了这个错误并按如下方式解决了这个问题:

原因是我忘了给予" ** - 细节" (view_name,例如:user-detail)命名空间。因此,Django Rest Framework无法找到该视图。

我的项目中有一个应用,假设我的项目名称为myproject,应用名称为myapp

有两个urls.py文件,一个是myproject/urls.py,另一个是myapp/urls.py。我在myproject/urls.py中为应用程序提供了一个命名空间,就像:

url(r'', include(myapp.urls, namespace="myapp")),

我在myapp/urls.py中注册了其余的框架路由器,然后出现了这个错误。

我的解决方案是明确地为url提供命名空间:

class UserSerializer(serializers.HyperlinkedModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name="myapp:user-detail")

    class Meta:
        model = User
        fields = ('url', 'username')

它解决了我的问题。

答案 2 :(得分:16)

也许有人可以看一下:http://www.django-rest-framework.org/api-guide/routers/

如果将命名空间与超链接序列化程序一起使用,则还需要确保序列化程序上的任何view_name参数都能正确反映命名空间。例如:

urlpatterns = [
    url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
    url(r'^api/', include(router.urls, namespace='api')),
]

您需要为超链接到用户详细信息视图的序列化程序字段添加view_name='api:user-detail'等参数。

class UserSerializer(serializers.HyperlinkedModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name="api:user-detail")

class Meta:
    model = User
    fields = ('url', 'username')

答案 3 :(得分:10)

此代码也应该有效。

class BottleSerializer(serializers.HyperlinkedModelSerializer):

  user = UserSerializer()

  class Meta:
    model = Bottle
    fields = ('url', 'wine', 'user')

答案 4 :(得分:9)

导致此错误的另一个令人讨厌的错误是在urls.py中不必要地定义了base_name。例如:

router.register(r'{pathname}, views.{ViewName}ViewSet, base_name='pathname')

这将导致上述错误。获取base_name outta并返回到工作API。下面的代码将修复错误。万岁!

router.register(r'{pathname}, views.{ViewName}ViewSet)

但是,您可能没有随意添加base_name,您可能已经这样做了,因为您为View定义了自定义def get_queryset(),因此Django要求您添加base_name。在这种情况下,您需要明确定义' url'作为有问题的序列化程序的HyperlinkedIdentityField。请注意,我们在抛出错误的视图的SERIALIZER上定义了这个HyperlinkedIdentityField。如果我的错误是"无法使用视图名称解析超链接关系的URL" study-detail"。您可能未能在API中包含相关模型,或者在此字段上错误地配置了lookup_field属性。"我可以使用以下代码修复此问题。

我的ModelViewSet(自定义get_queryset是我必须首先将base_name添加到router.register()的原因):

class StudyViewSet(viewsets.ModelViewSet):
    serializer_class = StudySerializer

    '''custom get_queryset'''
    def get_queryset(self):
        queryset = Study.objects.all()
        return queryset

我在urls.py中的此ModelViewSet的路由器注册:

router.register(r'studies', views.StudyViewSet, base_name='studies')

和这里的钱在哪里!然后我可以这样解决它:

class StudySerializer(serializers.HyperlinkedModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name="studies-detail")
    class Meta:
        model = Study
        fields = ('url', 'name', 'active', 'created',
              'time_zone', 'user', 'surveys')

是的。您必须在其自身上明确定义此HyperlinkedIdentityField才能使其正常工作。并且您需要确保HyperlinkedIdentityField上定义的view_name与您在urls.py中的base_name上定义的set(permutations(p)) 相同,并且' -detail'在它之后添加。

答案 5 :(得分:4)

今天,我遇到了同样的错误,下面的更改可以挽救我。

更改

class BottleSerializer(serializers.HyperlinkedModelSerializer):

收件人:

 class BottleSerializer(serializers.ModelSerializer):

答案 6 :(得分:2)

TL;DR:它可能就像从路由器基本名称中删除尾随的 's' 一样简单。无需在序列化程序中定义 url 字段。

对于原始海报,只需按照顶部答案中的建议注册 UserViewSet 即可解决该问题。

但是,如果其他人即使在所有 ViewSet 都已注册的情况下遇到此问题,我想我已经弄清楚出了什么问题,并且我找到了一个比这里的许多其他解决方案更简洁的解决方案。

就我而言,我在尝试使用自定义 get_queryset() 函数创建 ViewSet 后遇到了此问题。当我用自定义 get_queryset() 函数替换 ViewSet 的查询集字段时,我遇到了这个错误:

<块引用>

断言错误:未指定 `basename` 参数,无法从视图集自动确定名称,因为它没有 `.queryset` 属性。

所以,当然,我去了 urls.py 并修改了我的注册以包含一个基本名称:

router.register(r'messages', MessageViewSet, basename='messages')

但是后来我遇到了这个错误(正如我们在原始帖子中看到的那样):

<块引用>

无法使用视图名称“消息详细信息”解析超链接关系的 URL。您可能没有在 API 中包含相关模型,或者在此字段上错误地配置了 `lookup_field` 属性。

阅读DRF docs on routers后,我了解到路由器会自动为您生成两个url模式,它们有名称:

  1. 'basename-list'
  2. 'basename-detail'

因为我设置了 basename='messages'(注意末尾的 's'),我的 url 模式被命名为:

  1. '消息列表'
  2. '消息-详细信息'

由于 DRF 正在查找名为“message-detail”的 url 模式(请注意此处缺少“s”),我意识到我可以通过从基本名称中删除尾随的“s”来解决此问题 如此:

router.register(r'messages', MessageViewSet, basename='message')

我最终的序列化器和 ViewSet 实现就这么简单!

class MessageSerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = Message
        fields = ['url', 'message', 'timestamp', 'sender', ...]

class MessageViewSet(viewsets.ModelViewSet):
    serializer_class = MessageSerializer

    def get_queryset(self):
        return Message.objects.filter(...)

答案 7 :(得分:2)

相同错误,但原因不同:

我定义了一个自定义用户模型,没有新字段:

from django.contrib.auth.models import (AbstractUser)
class CustomUser(AbstractUser):
    """
    custom user, reference below example
    https://github.com/jonathanchu/django-custom-user-example/blob/master/customuser/accounts/models.py

    # original User class has all I need
    # Just add __str__, not rewrite other field
    - id
    - username
    - password
    - email
    - is_active
    - date_joined
    - method, email_user
    """

    def __str__(self):
        return self.username

这是我的观点功能:

from rest_framework import permissions
from rest_framework import viewsets
from .models import (CustomUser)
class UserViewSet(viewsets.ModelViewSet):
    permission_classes = (permissions.AllowAny,)
    serializer_class = UserSerializer

    def get_queryset(self):
        queryset = CustomUser.objects.filter(id=self.request.user.id)
        if self.request.user.is_superuser:
            queryset = CustomUser.objects.all()
        return queryset

由于我没有直接在queryset中提供UserViewSet,因此我必须在注册此视图集时设置base_name。这是由urls.py文件引起的错误消息:

from myapp.views import (UserViewSet)
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'users', UserViewSet, base_name='customuser')  # <--base_name needs to be 'customuser' instead of 'user'

您需要base_name与模型名称相同 - customuser

答案 8 :(得分:1)

如果您要扩展 GenericViewSet ListModelMixin 类,并且在列表视图中添加 url 字段时出现相同的错误,这是因为你没有定义细节视图。确保您正在扩展 RetrieveModelMixin mixin:

class UserViewSet (mixins.ListModelMixin,
                   mixins.RetrieveModelMixin,
                   viewsets.GenericViewSet):

答案 9 :(得分:1)

看来HyperlinkedModelSerializer与路径namespace不同。在我的应用程序中,我进行了两项更改。

# rootapp/urls.py
urlpatterns = [
    # path('api/', include('izzi.api.urls', namespace='api'))
    path('api/', include('izzi.api.urls')) # removed namespace
]

在导入的urls文件中

# app/urls.py
app_name = 'api' // removed the app_name

希望这会有所帮助。

答案 10 :(得分:0)

值得注意的是,如果您使用 action(打字错误?)创建 detail=False,则会引发此错误,请将其替换为 detail=True

@action(detail=True)
...

答案 11 :(得分:0)

在我的网址中添加命名空间后,我遇到了这个错误

 url('api/v2/', include('api.urls', namespace='v2')),

并将app_name添加到我的urls.py

我通过在项目的settings.py中为我的其余框架api指定NamespaceVersioning来解决此问题

REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.NamespaceVersioning'}

答案 12 :(得分:0)

我遇到了同样的问题,我认为您应该检查您的

get_absolute_url

对象模型的方法输入值(** kwargs)标题。 并在lookup_field中使用确切的字段名称

答案 13 :(得分:0)

如果您从序列化程序中省略了字段“ id”和“ url”,则不会有任何问题。无论如何,您都可以使用json对象中返回的ID来访问帖子,这使实现前端变得更加容易。

答案 14 :(得分:0)

我在这个错误中停留了将近2个小时:

在/ api_users / users / 1 /中配置不正确 无法使用视图名称“ users-detail”解析超链接关系的URL。您可能无法在API中包含相关模型,或者在此字段上错误地配置了lookup_field属性。

当我终于得到解决方案但不知道为什么时,所以我的代码是:

#models.py
class Users(models.Model):
    id          = models.AutoField(primary_key=True)
    name        = models.CharField(max_length=50, blank=False, null=False)
    email       = models.EmailField(null=False, blank=False) 
    class Meta:
        verbose_name = "Usuario"
        verbose_name_plural = "Usuarios"

    def __str__(self):
        return str(self.name)


#serializers.py
class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Users
        fields = (
            'id',
            'url',
            'name',        
            'email',       
            'description', 
            'active',      
            'age',         
            'some_date',   
            'timestamp',
            )
#views.py
class UserViewSet(viewsets.ModelViewSet):
    queryset = Users.objects.all()
    serializer_class = UserSerializer

#urls_api.py
router = routers.DefaultRouter()
router.register(r'users',UserViewSet, base_name='users')

urlpatterns = [ 
        url(r'^', include(router.urls)),
]

但是在我的主要网址中,是:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    #api users
    url(r'^api_users/', include('usersApi.users_urls', namespace='api')),

]

所以最终我解决了擦除命名空间的问题:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    #api users
    url(r'^api_users/', include('usersApi.users_urls')),

]

我终于解决了我的问题,所以任何人都可以让我知道为什么,最好。

答案 15 :(得分:0)

我遇到了同样的问题,并通过将generics.RetrieveAPIView作为基类添加到我的视图集来解决了这个问题。

答案 16 :(得分:0)

当数据库中的slug值为空(等于'')时,我在DRF 3.7.7上出现了该错误。

答案 17 :(得分:0)

Bottle = serializers.PrimaryKeyRelatedField(read_only = True)

read_only允许您表示字段,而无需将其链接到模型的另一个视图。

答案 18 :(得分:0)

我在遵循DRF快速入门指南时遇到了同样的错误 http://www.django-rest-framework.org/tutorial/quickstart/然后尝试浏览到/ users。我之前已多次完成此设置而没有任何问题。

我的解决方案不在代码中,而是替换数据库。

此安装与其他安装之间的区别在于我创建本地数据库。

这次我跑了

./manage.py migrate
./manage.py createsuperuser

运行后立即

virtualenv venv
. venv/bin/activate
pip install django
pip install djangorestframework

而不是指南中列出的确切顺序。

我怀疑在数据库中没有正确创建某些内容。我不关心我的dev db所以我删除了它并再次运行./manage.py migrate命令,创建了一个超级用户,浏览到/ users并且错误消失了。

我配置DRF和db的操作顺序有问题。

如果您正在使用sqlite并且能够测试更改为新的数据库,则在分析所有代码之前,值得尝试。