Overview
I'm setting up a new Django application with Django REST Framework (DRF), and this is my first time using the HyperlinkedModelSerializer
for the API endpoint.
I've overridden the get_queryset()
method on the ModelViewSet, so I've also the basename
argument to the application router and explicitly defined the url
attribute in the serializer as suggested here. This fixed issues that I was having with the model's own url
attribute.
However, I'm getting the following error message when trying to serialize a ForeignKey field of the same class as the parent model. It fails with the following message:
Could not resolve URL for hyperlinked relationship using view name "employee-detail". You may have failed to include the related model in your API, or incorrectly configured the
lookup_field
attribute on this field.
Is there something special in the serializer I need to do to support using recursive model relationships like this?
Example code
# app/models.py
from django.db import models
class AbstractBase(models.Model):
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class Employee(AbstractBase):
name = models.CharField(max_length=254)
manager = models.ForeignKey('self', related_name='direct_reports',
on_delete=models.SET_NULL, blank=True, null=True)
...
def __str__(self):
return str(self.name)
# app/views.py
from rest_framework import viewsets
from rest_framework.pagination import PageNumberPagination
from app import models
from app import serializers
# pagination defaults
class StandardResultsSetPagination(PageNumberPagination):
page_size = 25
page_size_query_param = 'page_size'
max_page_size = 1000
class EmployeeViewSet(viewsets.ModelViewSet):
pagination_class = StandardResultsSetPagination
serializer_class = serializers.EmployeeSerializer
http_method_names = ['options', 'get']
def get_queryset(self):
params = self.request.query_params
queryset = models.Employee.objects.all()
# apply url query filters...
return queryset
# app/serializers.py
from app import models
from rest_framework import serializers
class EmployeeSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedRelatedField(
read_only=True, view_name='employees-detail')
manager = serializers.HyperlinkedRelatedField(
read_only=True, view_name='employees-detail')
class Meta:
model = models.Employee
fields = ('url', 'name', 'manager')
# project/urls.py
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/', include('app.urls')),
]
# app/urls.py
from django.conf.urls import url, include
from rest_framework import routers
from app import views
router = routers.DefaultRouter(trailing_slash=False)
router.register(r'employees', views.EmployeeViewSet, basename='employees')
urlpatterns = [
url(r'^', include(router.urls)),
]