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

bpi*_*pat 92 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.
Run Code Online (Sandbox Code Playgroud)

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

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

我的序列化器:

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')
Run Code Online (Sandbox Code Playgroud)

我的观点:

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
Run Code Online (Sandbox Code Playgroud)

最后是网址:

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

urlpatterns = patterns('',
    url(r'^', include(router.urls)),
    # ...
Run Code Online (Sandbox Code Playgroud)

我没有用户详细信息视图,我也看不出这个问题可能来自哪里.有任何想法吗?

谢谢

Car*_*son 82

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

  1. 不只是注册UserViewSet与路由器解决您的问题?
  2. 您可以在您的用户字段上定义BottleSerializer以明确使用UserSerializer而不是尝试解析URL.有关处理嵌套对象的信息,请参阅序列化程序文档.

  • 这个要点----明确地做到这一点 - 很多魔法都会浪费很多时间. (3认同)

bov*_*son 54

我也遇到了这个错误并解决了如下:

原因是我忘了给命名空间"** - detail"(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")),
Run Code Online (Sandbox Code Playgroud)

我注册了其余的框架路由器myapp/urls.py,然后得到了这个错误.

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

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

    class Meta:
        model = User
        fields = ('url', 'username')
Run Code Online (Sandbox Code Playgroud)

它解决了我的问题.


小智 17

也许有人可以看看这个: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')),
]
Run Code Online (Sandbox Code Playgroud)

您需要包含一个参数,例如view_name='api:user-detail'超链接到用户详细信息视图的序列化程序字段.

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

class Meta:
    model = User
    fields = ('url', 'username')
Run Code Online (Sandbox Code Playgroud)

  • 总而言之,给你的 api 命名空间会导致标题中的错误,你可能不想这样做,除非你想在很多地方更改它。 (2认同)

cag*_*lar 10

这段代码也应该有效.

class BottleSerializer(serializers.HyperlinkedModelSerializer):

  user = UserSerializer()

  class Meta:
    model = Bottle
    fields = ('url', 'wine', 'user')
Run Code Online (Sandbox Code Playgroud)

  • 值得一提的是,必须实现`UserSerializer`(尚不能导入),如http://www.django-rest-framework.org/api-guide/serializers/中所示 (2认同)

Col*_*cks 9

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

router.register(r'{pathname}, views.{ViewName}ViewSet, base_name='pathname')
Run Code Online (Sandbox Code Playgroud)

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

router.register(r'{pathname}, views.{ViewName}ViewSet)
Run Code Online (Sandbox Code Playgroud)

但是,您可能不只是随意添加base_name,您可能已经这样做了,因为您为View定义了自定义def get_queryset(),因此Django要求您添加base_name.在这种情况下,您需要将"url"明确定义为相关序列化程序的HyperlinkedIdentityField.请注意,我们在抛出错误的视图的SERIALIZER上定义了这个HyperlinkedIdentityField.如果我的错误是"无法使用视图名称解析超链接关系的URL",请参阅"详细信息".您可能无法在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
Run Code Online (Sandbox Code Playgroud)

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

router.register(r'studies', views.StudyViewSet, base_name='studies')
Run Code Online (Sandbox Code Playgroud)

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

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

是的.您必须在其自身上明确定义此HyperlinkedIdentityField才能使其正常工作.并且您需要确保view_nameHyperlinkedIdentityField上的定义与您base_name在urls.py中定义的相同,并在其后添加了"-detail".

  • 这对我有用,但是我必须放置完整的路线 `<app_name>:studies-detail`。例如,如果我的应用程序名为 `tanks`,那么完整路径将是 `HyperlinkedIdentityField(view_name="tanks:studies-detail")`。为了弄清楚这一点,我使用了 [django-extensions](https://github.com/django-extensions/django-extensions) `show_urls` 命令,查看完整路由和路由器自动生成的标签。 (2认同)

小智 8

将命名空间添加到我的网址后遇到此错误

 url('api/v2/', include('api.urls', namespace='v2')),
Run Code Online (Sandbox Code Playgroud)

并将 app_name 添加到我的 urls.py

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

REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.NamespaceVersioning'}
Run Code Online (Sandbox Code Playgroud)


Ika*_*Chu 7

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

对于原始发帖者,只需按照最上面答案中的建议注册 UserViewSet 即可解决问题。

但是,如果其他人即使注册了所有 ViewSets 也遇到了这个问题,我想我已经弄清楚出了什么问题,并且我找到了一个比这里许多其他解决方案更干净的解决方案。

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

AssertionError:未指定“basename”参数,并且无法自动从视图集中确定名称,因为它没有“.queryset”属性。

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

router.register(r'messages', MessageViewSet, basename='messages')
Run Code Online (Sandbox Code Playgroud)

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

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

在阅读了routers 上的 DRF 文档后,我了解到路由器会自动为您生成两个 url 模式,它们的名称为:

  1. '基本名称列表'
  2. '基本名称-详细信息'

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

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

由于 DRF 正在寻找名为“message-detail”的 url 模式(请注意此处缺少“s”),我意识到只需从我的基名中删除尾随的“s”即可解决此问题

router.register(r'messages', MessageViewSet, basename='message')
Run Code Online (Sandbox Code Playgroud)

我最终的序列化器和 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(...)
Run Code Online (Sandbox Code Playgroud)


Man*_*Pal 6

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

改变

class BottleSerializer(serializers.HyperlinkedModelSerializer):
Run Code Online (Sandbox Code Playgroud)

到:

 class BottleSerializer(serializers.ModelSerializer):
Run Code Online (Sandbox Code Playgroud)