【问题标题】:Django Rest Framework - Could not resolve URL for hyperlinked relationship using view name "user-detail"Django Rest Framework - 无法使用视图名称“用户详细信息”解析超链接关系的 URL
【发布时间】:2013-12-31 06:47:38
【问题描述】:

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

无法使用视图名称“用户详细信息”解析超链接关系的 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)),
    # ...

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

谢谢

【问题讨论】:

  • 提到 bpipat 提出了我需要的相同问题,这是他的问题连续 3 次命中,但都有不同的错误

标签: python django django-rest-framework


【解决方案1】:

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

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

【讨论】:

  • 非常感谢,我在路由器中注释掉了 UserViewSet,解决了!
  • 这就是重点 ---- 明确地去做 --- 太多的魔法就是浪费太多的时间。
  • 它不起作用的原因是因为 django 想在当前视图中显示来自 User 的相关数据以获取参数 User。通常它会选择可用值的列表。由于未定义 UserViewSet,因此无法提取详细信息来呈现网页。在默认路由器下添加 UserViewSet 和注册使事情完成以呈现所有组件。
【解决方案2】:

我也遇到了这个错误,解决方法如下:

原因是我忘记给“**-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")),

我在myapp/urls.py注册了rest framework routers,然后就报这个错了。

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

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

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

它解决了我的问题。

【讨论】:

  • @boveson,这就像一个魅力!谢谢你解决了我几个小时的挫败感。
  • 这也使它对我有用。对我来说还有一个重要的一点是路线中 base_name 的正确拼写!
  • 这里的关键是命名空间前缀防止反向工作.....
  • 我遇到了这样的问题,经过 3 小时的搜索,这个答案解决了我的问题! @bovenson
  • 或者您可以按照 drf 的建议使用 extra_kwargs:extra_kwargs = {'url': {'view_name': 'myapp:user-detail'}}
【解决方案3】:

也许有人可以看看这个: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')

【讨论】:

  • 总结,给你的api一个命名空间会导致标题中的错误,除非你想在很多地方改变它,否则你可能不想这样做。
  • 为我工作!我的urls.py 被双重嵌套在我的newsite 项目中:(1)newsite/urls.py(由 django 创建)(2)polls/urls.py(3)polls/api/v1/urls.py............我必须使用url = serializers.HyperlinkedIdentityField(view_name="polls:polls_api:user-detail") 提及嵌套名称
【解决方案4】:

导致此错误的另一个严重错误是在您的 urls.py 中不必要地定义了 base_name。例如:

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

这将导致上述错误。从那里取出那个 base_name 并返回到一个正常工作的 API。下面的代码将修复错误。万岁!

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

但是,您可能不只是随意添加 base_name,您可能已经这样做了,因为您为 View 定义了自定义 def get_queryset(),因此 Django 要求您添加 base_name。在这种情况下,您需要将“url”显式定义为相关序列化程序的 HyperlinkedIdentityField。请注意,我们在引发错误的视图的序列化器上定义了这个 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

我在 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 上定义的相同,并在其后添加“-detail”。

【讨论】:

  • 这对我有用,但是我必须把完整的路线 <app_name>:studies-detail。例如,如果我的应用程序名为tanks,那么完整路径将为HyperlinkedIdentityField(view_name="tanks:studies-detail")。为了弄清楚这一点,我使用了django-exensionsshow_urls 命令来查看路由器自动制作的完整路由和标签。
【解决方案5】:

这段代码也应该可以工作。

class BottleSerializer(serializers.HyperlinkedModelSerializer):

  user = UserSerializer()

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

【讨论】:

  • 值得注意的是UserSerializer必须实现(它还没有准备好导入),如django-rest-framework.org/api-guide/serializers所示
  • 这对我有用,但为了让它工作,我必须将 router.register(r'bottles', views.BottleViewSet, base_name='bottles') 更改为 router.register(r'bottles' , 意见.BottleViewSet)。我不知道为什么需要进行此更改。
【解决方案6】:

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

改变

class BottleSerializer(serializers.HyperlinkedModelSerializer):

到:

 class BottleSerializer(serializers.ModelSerializer):

【讨论】:

    【解决方案7】:

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

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

    【讨论】:

      【解决方案8】:

      看来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
      

      希望这会有所帮助。

      【讨论】:

        【解决方案9】:

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

        对于最初的发帖者,该问题仅通过注册 UserViewSet 即可解决,如最佳答案中所建议的那样。

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

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

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

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

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

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

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

        看了DRF docs on routers,得知路由器会自动为你生成两个url模式,分别有名字:

        1. '基本名称列表'
        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(...)
        

        【讨论】:

          【解决方案10】:

          同样的错误,但不同的原因:

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

          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
          

          由于我没有直接在UserViewSet中给queryset,所以我注册这个viewset的时候必须设置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

          【讨论】:

          • 旧帖子,但您的评论“#
          【解决方案11】:

          如果您正在扩展 GenericViewSetListModelMixin 类,并且在列表视图中添加 url 字段时遇到相同的错误,这是因为您没有定义详细视图。确保您正在扩展 RetrieveModelMixin 混合:

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

          【讨论】:

          • 你是生命之神!
          【解决方案12】:

          有点晚,但在 Django 3 及更高版本中,include 不支持 namespace 而不指定 app_name。检查include的源代码,我们看到条件

          if namespaces and not app_name:
              ....
          

          已检查。仍然从源代码中,app_name 是这样的;

          urlconf_module, app_name = arg
          

          其中arginclude 的第一个参数。这告诉我们,我们的include 应该定义为

          include((app.urls, app_name), namespace='...')
          

          示例

          假设您有一个项目 myproject 和一个应用程序 myapp。然后你想建立一个地址。您应该使用视图集并如下定义路由器

          myapp.urls

          router.register('address', exampleviewset, basename='address')
          

          myproject.urls

          path('api/v1/', include(('myapp.urls', 'myapp'), namespace='myapp')),
          

          serializers.py

          class AddressSerializer(serializers.HyperlinkedModelSerializer):
              url = serializers.HyperlinkedIdentityField(view_name="myapp:address-detail")
              class Meta:
                  model = Address
                  fields = ('url',...)
          

          显然,我们不能使用fields='__all__'。我们必须明确包含url 并列出我们需要的剩余字段。

          【讨论】:

            【解决方案13】:

            我在遵循 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
            

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

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

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

            如果您使用 sqlite 并且能够测试更改为新数据库,那么在剖析所有代码之前值得尝试一下。

            【讨论】:

              【解决方案14】:

              Bottle = serializers.PrimaryKeyRelatedField(read_only=True)

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

              【讨论】:

                【解决方案15】:

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

                【讨论】:

                  【解决方案16】:

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

                  【讨论】:

                    【解决方案17】:

                    我在这个错误中卡住了将近 2 个小时:

                    在 /api_users/users/1/ 处配置不正确 无法使用视图名称“用户详细信息”解析超链接关系的 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')),
                    
                    ]
                    

                    我终于解决了我的问题,所以任何人都可以告诉我原因,最好的。

                    【讨论】:

                      【解决方案18】:

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

                      【讨论】:

                        【解决方案19】:

                        我有同样的问题,我认为你应该检查你的

                        get_absolute_url

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

                        【讨论】:

                        • 我的模型没有get_absolute_url。它也没有为 django User 模型声明。虽然我自己的模型有问题,但我没有用户模型。
                        【解决方案20】:

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

                        @action(detail=True)
                        ...
                        

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 2017-02-25
                          • 2022-11-13
                          • 2021-08-16
                          • 2018-06-29
                          • 2015-01-15
                          • 2021-07-10
                          • 2018-08-27
                          • 2019-08-20
                          相关资源
                          最近更新 更多