Install & Compatibility
Where this runs
tested against v0.95.3 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.95 runs
installs and imports cleanly · install 0.0s · import 0.000s · 70.7MB
glibcpy 3.10–3.95 runs
installs and imports cleanly · install 3.7s · import 0.000s · 71MB
70MB installed
● package 70MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
NestedRouter
✓ from rest_framework_nested import NestedRouter
✗ from rest_framework_nested.routers import NestedRouter
This quickstart demonstrates how to set up nested routes for `Domains` and their `Nameservers`. It uses `DefaultRouter` for the base resource and `NestedDefaultRouter` for the nested resource. The `lookup` argument in `NestedDefaultRouter` specifies the URL keyword argument that will be used to filter child resources (e.g., `domain_pk`). The `basename` argument is crucial for correctly generating URL patterns and reverse lookups, especially for the nested router.
from django.db import models
from rest_framework import viewsets, serializers
from rest_framework_nested import routers
from django.urls import path, include
# models.py
class Domain(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
class Nameserver(models.Model):
domain = models.ForeignKey(Domain, related_name='nameservers', on_delete=models.CASCADE)
hostname = models.CharField(max_length=255)
def __str__(self):
return f'{self.hostname} ({self.domain.name})'
# serializers.py (Optional, for hyperlinked relations)
class NameserverSerializer(serializers.ModelSerializer):
class Meta:
model = Nameserver
fields = ['id', 'hostname']
class DomainSerializer(serializers.ModelSerializer):
nameservers = NameserverSerializer(many=True, read_only=True)
class Meta:
model = Domain
fields = ['id', 'name', 'nameservers']
# views.py
class DomainViewSet(viewsets.ModelViewSet):
queryset = Domain.objects.all()
serializer_class = DomainSerializer
class NameserverViewSet(viewsets.ModelViewSet):
serializer_class = NameserverSerializer
def get_queryset(self):
return self.queryset.filter(domain=self.kwargs['domain_pk'])
def perform_create(self, serializer):
domain = Domain.objects.get(pk=self.kwargs['domain_pk'])
serializer.save(domain=domain)
# urls.py
router = routers.DefaultRouter()
router.register(r'domains', DomainViewSet, basename='domain')
domains_router = routers.NestedDefaultRouter(router, r'domains', lookup='domain')
domains_router.register(r'nameservers', NameserverViewSet, basename='domain-nameserver')
urlpatterns = [
path('', include(router.urls)),
path('', include(domains_router.urls)),
]
# Example usage in a Django project's main urls.py:
# from django.urls import path, include
# from myapp import urls as myapp_urls
# urlpatterns = [
# path('api/', include(myapp_urls)),
# ]
Debug
Known issues
breakingVersion 0.94.2 and later dropped support for Python 3.8 and older, Django 4.1 and older, and DRF 3.13 and older. Version 0.93.5 dropped support for Python 3.6, Django 1.11, and DRF 3.6.fixUpgrade your Python, Django, and Django REST Framework versions to meet the minimum requirements of `drf-nested-routers` 0.94.2+: Python >=3.9, Django >=4.2, DRF >=3.14. Always consult the project's `requirements.txt` or GitHub README for precise compatibility.
affects: <0.94.2 for Python 3.8, Django <4.2, DRF <3.14; <0.93.5 for Python 3.7, Django <3.2, DRF <3.14
gotchaThe `lookup` parameter in `NestedSimpleRouter` or `NestedDefaultRouter` must match the URL keyword argument expected for the parent resource in the URL pattern and the corresponding lookup in the child ViewSet.fixEnsure `lookup='parent'` in `Nested*Router` matches the `{parent_pk}` in the URL pattern. Your child `ViewSet`'s `get_queryset` method will access this via `self.kwargs['parent_pk']`. For example, `lookup='domain'` expects `domain_pk` in the URL and `self.kwargs['domain_pk']` in the ViewSet. affects: All versions
gotchaWhen using `NestedHyperlinkedModelSerializer` for nested hyperlinks, you must define `parent_lookup_kwargs` in its `Meta` class to correctly build the parent resource's URL. This maps URL keyword arguments to model fields.fixIn your `NestedHyperlinkedModelSerializer`, add `parent_lookup_kwargs = {'parent_pk': 'parent__pk'}` (or similar, matching your model relationships and URL lookups). affects: All versions
gotchaWhen registering a ViewSet with `Nested*Router.register()`, particularly if the ViewSet does not have a `queryset` attribute or a clear `model` attribute (e.g., a custom `ViewSet`), you *must* provide a `basename` argument.fixAlways explicitly define `basename='your-resource-name'` when calling `router.register()` to ensure correct URL pattern generation and reverse lookup functionality. This helps DRF correctly name the URL patterns. For example, `domains_router.register(r'nameservers', NameserverViewSet, basename='domain-nameserver')`.
affects: All versions
Upgrade
Version history
0.95.3latest on PyPI · released Jul 31, 2026
Audit
Dependencies
DjangorequiredRequired for the web framework integration.
djangorestframeworkrequiredThe core framework that this library extends.