Here’s an error that’s all too easy to stumble on if you are just hacking your way into an API using Django REST Framework

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

Recreating the error

I’ll assume you have, at least, a basic Django site up and running. Perhaps you are a little impatient (like me) and you skim the Django REST Framework’s homepage. You add the following in to settings.py:

REST_FRAMEWORK = { # Use hyperlinked styles by default. # Only used if the `serializer_class` attribute is not set on a view. 'DEFAULT_MODEL_SERIALIZER_CLASS': 'rest_framework.serializers.HyperlinkedModelSerializer', # Use Django's standard `django.contrib.auth` permissions, # or allow read-only access for unauthenticated users. 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly' ] }

And then, somehow, you skip the rest of the tutorial and you end up with something like this:

class Pet(models.Model): name = models.CharField(max_length=250) date_of_birth = models.DateTimeField() def __unicode__(self): return self.name ## views.py: from .models import Pet from rest_framework.generics import( ListCreateAPIView ) class PetAPIListCreateView(ListCreateAPIView): model = Pet ## urls.py: from django.conf.urls import patterns, include, url from .views import PetAPIListCreateView urlpatterns = patterns('', url(r'^api/$', PetAPIListCreateView.as_view()), )

Make sure you run your migration or sync your db.

Now you should be able to browse your api with the following url:

http://localhost:8000/pets/api

Things are looking good, job done? Not so fast……spend a moment inserting a record into the Pet table – create a fixture, write some raw sql, whatever floats your boat. Refresh your api endpoint and you’ll get a glorious error:

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

How do you dig yourself out of this one?

Two methods – the first (possibly simplest) is to cut the following out of settings.py (commented out so you don’t skim my post and add it in again):

#REST_FRAMEWORK = { # # Use hyperlinked styles by default. # # Only used if the `serializer_class` attribute is not set on a view. # 'DEFAULT_MODEL_SERIALIZER_CLASS': # 'rest_framework.serializers.HyperlinkedModelSerializer', # # # Use Django's standard `django.contrib.auth` permissions, # # or allow read-only access for unauthenticated users. # 'DEFAULT_PERMISSION_CLASSES': [ # 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly' # ] #}

In actual fact, removing just the following two lines will fix it for you:

#'DEFAULT_MODEL_SERIALIZER_CLASS': #'rest_framework.serializers.HyperlinkedModelSerializer',

The second is to create a serializers.py class like so:

from rest_framework import serializers from .models import Pet class PetSerializer(serializers.ModelSerializer): class Meta: model=Pet fields =('id','name','date_of_birth')

and update your views.py as follows:

from .models import Pet from .serializers import PetSerializer from rest_framework.generics import( ListCreateAPIView ) class PetAPIListCreateView(ListCreateAPIView): queryset = Pet.objects.all() serializer_class = PetSerializer

and you will be back in the land of the living.

Why does this happen?

Well, the key lies in the Default Model Serializer Class – when it is set to HyperlinkedModelSerializer, the rest framework needs a serializer to work with.

Kvetch

The error message here is really, really unhelpful for a anyone not familiar with the Django Rest Framework.

Could not resolve URL for hyperlinked relationship using view name “pet-detail”

made me start questioning my sanity – I had neither a detail suffix view defined, nor any sort of relationship with another model – both things I thought would be obvious causes of the error.

The added annoyance of the bug on rearing its head when data is populated also irked me somewhat because as part of my bug exploration, I created a new stripped down project (as above) to test the damn thing out. I didn’t include any fixtures in my test project, so initially, it looked like it worked and spent a hunk of time back in my original application looking for bugs in “my” code rather than default settings of the REST framework itself.

Ultimately the lesson is: RTFM? Well yes and no. I do think that projects should have an “at a glance” page, and I erroneously thought the Django REST Framework’s homepage would be it – you know “whack this in your app and you’ll have a basic json response going” type of thing. Of course this is a case where I should have read just a little bit more to save myself a headache.

Aah well, live and learn.