CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-djangorestframework

Web APIs for Django, made easy.

Pending
Overview
Eval results
Files

routers-urls.mddocs/

Routers and URL Patterns

Automatic URL pattern generation for ViewSets with support for nested routes and custom actions in Django REST Framework.

Capabilities

Router Classes

Router classes automatically generate URL patterns from ViewSet registrations.

class BaseRouter:
    """
    Base class for all router implementations.
    """
    def __init__(self):
        self.registry = []  # List of registered viewsets
    
    def register(self, prefix, viewset, basename=None):
        """
        Register a viewset with the router.
        
        Args:
            prefix (str): URL prefix for the viewset
            viewset: ViewSet class to register
            basename (str): Base name for URL patterns
        """
    
    def get_urls(self):
        """
        Generate URL patterns for all registered viewsets.
        
        Returns:
            list: Django URL patterns
        """
    
    def get_api_root_view(self, api_urls=None):
        """
        Create API root view showing available endpoints.
        
        Args:
            api_urls: URL patterns to include in root
            
        Returns:
            APIView: Root view class
        """
    
    def get_default_basename(self, viewset):
        """
        Get default basename from viewset's queryset model.
        
        Args:
            viewset: ViewSet class
            
        Returns:
            str: Default basename
        """

class SimpleRouter(BaseRouter):
    """
    Simple router generating basic URL patterns.
    """
    routes = [  # URL pattern templates
        # List route: /prefix/
        Route(
            url=r'^{prefix}{trailing_slash}$',
            mapping={'get': 'list', 'post': 'create'},
            name='{basename}-list',
            detail=False,
            initkwargs={'suffix': 'List'}
        ),
        # Detail route: /prefix/{lookup}/
        Route(
            url=r'^{prefix}/{lookup}{trailing_slash}$',
            mapping={
                'get': 'retrieve',
                'put': 'update', 
                'patch': 'partial_update',
                'delete': 'destroy'
            },
            name='{basename}-detail',
            detail=True,
            initkwargs={'suffix': 'Instance'}
        ),
    ]
    
    def __init__(self, trailing_slash=True):
        """
        Args:
            trailing_slash (bool): Include trailing slash in URLs
        """
        self.trailing_slash = '/' if trailing_slash else ''
        super().__init__()

class DefaultRouter(SimpleRouter):
    """
    Default router with API root view and optional format suffixes.
    """
    include_root_view = True      # Include API root endpoint
    include_format_suffixes = True  # Include format suffixes (.json, .xml)
    root_view_name = 'api-root'   # Name for root view
    default_schema_renderers = None  # Schema renderers for root view
    
    def get_api_root_view(self, api_urls=None):
        """
        Create browsable API root view.
        
        Returns:
            APIRootView: Root view showing available endpoints
        """

Route Configuration Classes

Classes defining URL route patterns and mappings.

Route = namedtuple('Route', [
    'url',          # URL pattern template
    'mapping',      # HTTP method to viewset action mapping
    'name',         # URL pattern name template
    'detail',       # Whether route is for detail views
    'initkwargs'    # Additional viewset initialization kwargs
])

DynamicRoute = namedtuple('DynamicRoute', [
    'url',          # URL pattern template  
    'name',         # URL pattern name template
    'detail',       # Whether route is for detail views
    'initkwargs'    # Additional viewset initialization kwargs
])

API Root View

Automatically generated root view for browsable API.

class APIRootView(APIView):
    """
    Default API root view providing links to registered endpoints.
    """
    _ignore_model_permissions = True
    schema = None  # Disable schema generation for root
    api_root_dict = None  # Dictionary of available endpoints
    
    def get(self, request, *args, **kwargs):
        """
        Return links to all available API endpoints.
        
        Returns:
            Response: Dictionary of endpoint names and URLs
        """

URL Pattern Utilities

Utilities for working with URL patterns and format suffixes.

def format_suffix_patterns(urlpatterns, suffix_required=False, allowed=None):
    """
    Add format suffix patterns to existing URL patterns.
    
    Args:
        urlpatterns (list): Existing URL patterns
        suffix_required (bool): Whether format suffix is required
        allowed (list): List of allowed format suffixes
        
    Returns:
        list: URL patterns with format suffix support
    """

def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required, allowed):
    """
    Apply suffix patterns to URL patterns.
    
    Args:
        urlpatterns (list): URL patterns to modify
        suffix_pattern (str): Suffix pattern template
        suffix_required (bool): Whether suffix is required
        allowed (list): Allowed suffix values
        
    Returns:
        list: Modified URL patterns
    """

Usage Examples

Basic Router Setup

# urls.py
from rest_framework.routers import DefaultRouter
from myapp.views import BookViewSet, AuthorViewSet

# Create router instance
router = DefaultRouter()

# Register viewsets
router.register(r'books', BookViewSet)
router.register(r'authors', AuthorViewSet)

# Include router URLs
urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include(router.urls)),
    path('api-auth/', include('rest_framework.urls')),
]

# Generated URLs:
# /api/ (API root)
# /api/books/ (list/create books)
# /api/books/{id}/ (retrieve/update/delete book)
# /api/authors/ (list/create authors)
# /api/authors/{id}/ (retrieve/update/delete author)

Custom Basename and ViewSet Actions

from rest_framework.viewsets import ModelViewSet
from rest_framework.decorators import action
from rest_framework.response import Response

class BookViewSet(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    
    @action(detail=True, methods=['post'])
    def set_favorite(self, request, pk=None):
        """Mark book as favorite for current user."""
        book = self.get_object()
        # Custom logic here
        return Response({'status': 'favorite set'})
    
    @action(detail=False, methods=['get'])
    def recent(self, request):
        """Get recently published books."""
        recent_books = self.queryset.filter(
            publication_date__gte=timezone.now() - timedelta(days=30)
        )
        serializer = self.get_serializer(recent_books, many=True)
        return Response(serializer.data)
    
    @action(detail=True, methods=['get'], url_path='reviews')
    def book_reviews(self, request, pk=None):
        """Get reviews for specific book."""
        book = self.get_object()
        reviews = book.reviews.all()
        # Serialize and return reviews
        return Response(review_data)

# Register with custom basename
router.register(r'books', BookViewSet, basename='book')

# Generated URLs include custom actions:
# /api/books/{id}/set_favorite/ (POST)
# /api/books/recent/ (GET)
# /api/books/{id}/reviews/ (GET)

Multiple Routers and Nested URLs

# Main router for primary resources
main_router = DefaultRouter()
main_router.register(r'books', BookViewSet)
main_router.register(r'authors', AuthorViewSet)

# Secondary router for admin resources
admin_router = SimpleRouter()
admin_router.register(r'users', UserViewSet)
admin_router.register(r'logs', LogViewSet)

# Combine routers
urlpatterns = [
    path('api/v1/', include(main_router.urls)),
    path('api/admin/', include(admin_router.urls)),
    # Manual URL patterns can be mixed in
    path('api/auth/', include('rest_framework.authtoken.urls')),
]

Custom Router with Special Routes

from rest_framework.routers import Route, DynamicRoute, SimpleRouter

class CustomRouter(SimpleRouter):
    """
    Custom router with additional route patterns.
    """
    routes = [
        # Standard list route
        Route(
            url=r'^{prefix}{trailing_slash}$',
            mapping={'get': 'list', 'post': 'create'},
            name='{basename}-list',
            detail=False,
            initkwargs={'suffix': 'List'}
        ),
        # Custom bulk route
        Route(
            url=r'^{prefix}/bulk{trailing_slash}$',
            mapping={'post': 'bulk_create', 'patch': 'bulk_update'},
            name='{basename}-bulk',
            detail=False,
            initkwargs={}
        ),
        # Standard detail route
        Route(
            url=r'^{prefix}/{lookup}{trailing_slash}$',
            mapping={
                'get': 'retrieve',
                'put': 'update',
                'patch': 'partial_update',
                'delete': 'destroy'
            },
            name='{basename}-detail',
            detail=True,
            initkwargs={'suffix': 'Instance'}
        ),
        # Dynamic routes for @action decorated methods
        DynamicRoute(
            url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$',
            name='{basename}-{url_name}',
            detail=True,
            initkwargs={}
        ),
        DynamicRoute(
            url=r'^{prefix}/{url_path}{trailing_slash}$',
            name='{basename}-{url_name}',
            detail=False,
            initkwargs={}
        ),
    ]

# Usage
custom_router = CustomRouter()
custom_router.register(r'books', BookViewSet)

# Now supports bulk operations:
# POST /api/books/bulk/ -> bulk_create
# PATCH /api/books/bulk/ -> bulk_update

Format Suffix Patterns

from rest_framework.urlpatterns import format_suffix_patterns

# Manual URL patterns with format suffixes
urlpatterns = [
    path('books/', BookListView.as_view(), name='book-list'),
    path('books/<int:pk>/', BookDetailView.as_view(), name='book-detail'),
]

# Add format suffix support
urlpatterns = format_suffix_patterns(urlpatterns)

# Now supports:
# /books/ or /books.json or /books.xml
# /books/1/ or /books/1.json or /books/1.xml

# Custom allowed formats
urlpatterns = format_suffix_patterns(
    urlpatterns, 
    allowed=['json', 'xml', 'yaml']
)

# Required suffix
urlpatterns = format_suffix_patterns(
    urlpatterns,
    suffix_required=True  # Must include format suffix
)

Router without Root View

# Simple router without API root
simple_router = SimpleRouter()
simple_router.register(r'books', BookViewSet)

# Default router without root view
no_root_router = DefaultRouter()
no_root_router.include_root_view = False
no_root_router.register(r'books', BookViewSet)

# Custom trailing slash behavior
no_slash_router = DefaultRouter(trailing_slash=False)
no_slash_router.register(r'books', BookViewSet)

# URLs without trailing slashes:
# /api/books (instead of /api/books/)
# /api/books/1 (instead of /api/books/1/)

Debugging Router URLs

# Print all generated URLs for debugging
router = DefaultRouter()
router.register(r'books', BookViewSet)
router.register(r'authors', AuthorViewSet)

# Get all URL patterns
url_patterns = router.urls

for pattern in url_patterns:
    print(f"Pattern: {pattern.pattern}")
    print(f"Name: {pattern.name}")
    print(f"Callback: {pattern.callback}")
    print("---")

Utility Functions

def escape_curly_brackets(url_path):
    """
    Escape curly brackets in URL path for regex patterns.
    
    Args:
        url_path (str): URL path that may contain curly brackets
        
    Returns:
        str: Escaped URL path
    """

def flatten(list_of_lists):
    """
    Flatten nested lists into single list.
    
    Args:
        list_of_lists (list): Nested list structure
        
    Returns:
        list: Flattened list
    """

def format_suffix_patterns(urlpatterns, suffix_required=False, allowed=None):
    """
    Add format suffix patterns to URL patterns.
    
    Args:
        urlpatterns (list): List of URL patterns
        suffix_required (bool): Whether format suffix is required
        allowed (list): List of allowed format suffixes
        
    Returns:
        list: URL patterns with format suffix support
    """

def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required, suffix_route=None):
    """
    Apply suffix patterns to URL pattern list recursively.
    Internal function used by format_suffix_patterns.
    
    Args:
        urlpatterns (list): URL patterns to process
        suffix_pattern (str): Suffix pattern regex
        suffix_required (bool): Whether suffix is required
        suffix_route (str): Optional route suffix
        
    Returns:
        list: Processed URL patterns
    """

Install with Tessl CLI

npx tessl i tessl/pypi-djangorestframework

docs

auth-permissions.md

content-negotiation.md

decorators.md

fields-validation.md

generic-views.md

index.md

pagination-filtering.md

request-response.md

routers-urls.md

serializers.md

status-exceptions.md

testing.md

views-viewsets.md

tile.json