Django Rest Framework - Could not resolve URL for hyperlinked relationship using view name "user-detail"

Viewed 88950

I am building a project in Django Rest Framework where users can login to view their wine cellar. My ModelViewSets were working just fine and all of a sudden I get this frustrating error:

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.

The traceback shows:

    [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.

I have a custom email user model and the bottle model in models.py is:

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

My serializers:

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

My views:

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

and finally the url:

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

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

I don't have a user detail view and I don't see where this issue could come from. Any ideas?

Thanks

21 Answers

Today, I got the same error and below changes rescue me.

Change

class BottleSerializer(serializers.HyperlinkedModelSerializer):

to:

 class BottleSerializer(serializers.ModelSerializer):

I ran into this error after adding namespace to my url

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

and adding app_name to my urls.py

I resolved this by specifying NamespaceVersioning for my rest framework api in settings.py of my project

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

TL;DR: It may be as simple as removing a trailing 's' from the router basename. No need to define a url field in your serializer.

For the original poster, the issue was resolved simply by registering the UserViewSet, as suggested in the top answer.

However, if anyone else has this issue even with all ViewSets registered, I think I've figured out what's going wrong, and I've found a solution that's cleaner than a lot of the others here.

In my case, I encountered this issue after trying to create a ViewSet with a custom get_queryset() function. When I replaced the ViewSet's queryset field with a custom get_queryset() function, I was then hit with this error:

AssertionError: `basename` argument not specified, and could not automatically determine the name from the viewset, as it does not have a `.queryset` attribute.

So, of course, I went to urls.py and modified my registration to include a basename as such:

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

But then I was hit with this error (as we see in the original post):

Could not resolve URL for hyperlinked relationship using view name "message-detail". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.

After reading the DRF docs on routers, I learned that the router automatically generates two url patterns for you, which have names:

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

Because I set my basename='messages' (note the 's' at the end), my url patterns were named:

  1. 'messages-list'
  2. 'messages-detail'

Since DRF was looking a url pattern named 'message-detail' (note here the lack of 's'), I realized that I could resolve this simply by removing the trailing 's' from my basename as such:

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

My final serializer and ViewSet implementations were as simple as this!

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(...)

It appears that HyperlinkedModelSerializer do not agree with having a path namespace. In my application I made two changes.

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

In the imported urls file

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

Hope this helps.

A bit late but in Django 3 and above, include doesn't support namespace without specifying the app_name. Checking the source code for include, we see that the condition

if namespaces and not app_name:
    ....

is checked. And still from the source code, app_name is gotten like;

urlconf_module, app_name = arg

where arg is the first argument of the include. This tells us that, our include should be defined as

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

Example

Say you have a project myproject and an app myapp. Then you want to establish an address. You should use a viewset and define a router as below

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

Apparently, we can't use fields='__all__'. We must include url explicitly and list the remaining fields we need.

I ran into this same issue and resolved it by adding generics.RetrieveAPIView as a base class to my viewset.

I was stuck in this error for almost 2 hours:

ImproperlyConfigured at /api_users/users/1/ Could not resolve URL for hyperlinked relationship using view name "users-detail". You may have failed to include the related model in your API, or incorrectly configured the lookup_field attribute on this field.

When I finally get the solution but I don't understand why, so my code is:

#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)),
]

but in my main URLs, it was:

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

]

So to finally I resolve the problem erasing namespace:

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

]

And I finally resolve my problem, so any one can let me know why, bests.

If you omit the fields 'id' and 'url' from your serializer you won't have any problem. You can access to the posts by using the id that is returned in the json object anyways, which it makes it even easier to implement your frontend.

I had the same problem , I think you should check your

get_absolute_url

object model's method input value (**kwargs) title. and use exact field name in lookup_field

It is worth noting that if you create an action with detail=False (typo?) then this errors will be raised, replace it with detail=True:

@action(detail=True)
...

I wanted to stay with everything as-is out of the box so I just added a User serializer:

class UserSerializer(serializers.HyperlinkedModelSerializer):

class Meta:
    model = User
    fields = ['id', 'username']

A Viewset:

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

And added to urls:

router.register(r'users', UserViewSet)
Related