I try to use Django Rest Framework (DRF) with HyperlinkedModelSerializers, ViewSets and a Routers.
When I check the generated routes, Django shows me vehicle-detail
, but DRF complains with an error:
ImproperlyConfigured at /api/vehicles/
Could not resolve URL for hyperlinked relationship using view name "vehicle-detail". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.
The code below works well if a leave out the url
from fields.
Anyone an idea what is missing?
urls.py
from rest_framework.routers import DefaultRouter
from vehicles import viewsets
# Create a router and register our ViewSets with it.
router = DefaultRouter()
router.register(r'vehicles',
viewsets.VehicleViewSet,
basename='vehicle')
# The API URLs are now determined automatically by the router.
urlpatterns = [
path('', include(router.urls)),
]
vehicles/viewsets.py
class VehicleViewSet(viewsets.ModelViewSet):
queryset = Vehicle.objects.all()
serializer_class = VehicleSerializer
vehicles/serializers.py
class VehicleSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Vehicle
fields = ['url', 'name', 'description']
# fields = ['name', 'description'] # Removed 'url'. Now the API works
Generated URLs
api/ ^vehicles/$ [name='vehicle-list']
api/ ^vehicles.(?P<format>[a-z0-9]+)/?$ [name='vehicle-list']
api/ ^vehicles/(?P<pk>[^/.]+)/$ [name='vehicle-detail']
api/ ^vehicles/(?P<pk>[^/.]+).(?P<format>[a-z0-9]+)/?$ [name='vehicle-detail']
api/ [name='api-root']
api/ <drf_format_suffix:format> [name='api-root']
pip freeze
Django 5.1
djangorestframework 3.15.2
1
The problem was url namespaces!
On https://www.django-rest-framework.org/api-guide/routers/ it states:
If using namespacing with hyperlinked serializers you’ll also need to ensure that any view_name parameters on the serializers correctly reflect the namespace. In the examples above you’d need to include a parameter such as view_name=’app_name:user-detail’ for serializer fields hyperlinked to the user detail view.
Django main urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('api/auth/', include('rest_framework.urls', namespace='rest_framework')),
path('api/', include(('api.urls', 'api'), namespace='api')),
]
Solution
I use the namespace api in path('api/', include(('api.urls', 'api'), namespace='api'))
.
I need to provide the namespace in the serializer as well:
class VehicleSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='api:vehicle-detail')
class Meta:
model = Vehicle
fields = ['url', 'name', 'description']
Alternatively, instead of defining the url
attribute, we can provide extra_kwargs:
class VehicleSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Vehicle
fields = ['url', 'name', 'description']
extra_kwargs = {
'url': {'view_name': 'api:vehicle-detail'},
}