URL Routing System

Django-Vibe provides a powerful class-based URL routing system that simplifies URL configuration in Django applications. It offers automatic namespace handling, inheritance, and easy management of complex URL hierarchies.

Overview

The URL routing system is built around the concept of Viewset classes, which define URL patterns in a declarative, object-oriented way. This approach makes it easier to organize, extend, and maintain URL configurations compared to the standard Django approach.

from django.views.generic import TemplateView
from django.urls import path
from material.urls import Viewset, route

class MyViewset(Viewset):
    app_name = "myapp"
    
    # Define URL patterns as class attributes
    home_path = path("", TemplateView.as_view(template_name="myapp/home.html"), name="home")
    about_path = path("about/", TemplateView.as_view(template_name="myapp/about.html"), name="about")
    
    # Nest another viewset
    admin_path = route("admin/", AdminViewset())

# Use in your urls.py
urlpatterns = [
    path("", MyViewset().urls)
]

Key Features

Declarative URL Definition

Define URLs as class attributes ending with _path. This makes URL configurations more readable and maintainable compared to traditional Django URL patterns.

Automatic Namespace Handling

Viewsets automatically handle URL namespaces based on the app_name and namespace attributes. This simplifies URL resolution in templates and views.

Nested Viewsets

Easily nest viewsets using the route() function. This creates a hierarchical URL structure that matches your application's organization.

Inheritance Support

Extend existing viewsets to inherit and override URL patterns. This promotes code reuse and simplifies creating variations of URL configurations.

Index Redirect

The IndexViewMixin automatically creates a redirect from the root URL to the first suitable URL pattern, eliminating the need for explicit redirects.

API Reference

BaseViewset

Base class for defining class-based URL routing configurations. It provides the core functionality for managing URLs, namespaces, and parent-child relationships.

Attribute/Method
Type
Description
app_name str The application name for URL namespacing
namespace str Explicit namespace for URLs
parent_namespace str Namespace of the parent viewset
urls property Returns URL patterns, app name, and namespace
reverse() method Generates a URL for a given view name with proper namespacing

Viewset

Extends BaseViewset with the ability to collect URL patterns from class attributes and handle nested viewsets.

Attribute/Method
Type
Description
viewsets list Additional viewsets to include in the URL configuration
urlpatterns list Additional URL patterns to include
declared_patterns dict Collected URL patterns from class attributes

Site

A top-level Viewset designed for creating site-wide URL structures. It manages multiple applications and provides features for consistent site navigation.

Attribute/Method
Type
Description
title str Site title, auto-generated from class name if not specified
icon str Default material icon for the site (default: "view_comfy")
menu_template_name str Template for rendering the site menu
primary_color str Primary theme color for the site
secondary_color str Secondary theme color for the site
permission str Required permission for viewing the site
menu_items() method Returns an iterator of Site or Application viewsets for menu building
register() method Register an Application class with the site
get_absolute_url() method Resolve URL for a model object in any registered viewset

Application

A Viewset designed for creating application-specific URL structures. It provides menu integration and consistent navigation within a specific application section.

Attribute/Method
Type
Description
title str Application title, auto-generated from class name if empty
icon str Default material icon for the application (default: "view_module")
menu_template_name str Template for rendering the application menu
base_template_name str Base template used for application views
permission str | callable Required permission or permission check function
menu_items() method Returns an iterator of AppMenuMixin viewsets for menu building
get_context_data() method Returns context data for application templates

AppMenuMixin

A mixin that enables a viewset to be included in application menus. It provides consistent title and icon presentation, with automatic title generation.

Attribute/Method
Type
Description
title str Menu item title, auto-generated from class name if None
icon str Material icon for the menu item (default: "view_carousel")
has_view_permission() method Check if the user has permission to view this menu item

route

Function that creates a route mapping a URL prefix to a viewset.

route(prefix: str, viewset: BaseViewset) -> Route

# Example
admin_path = route("admin/", AdminViewset())

IndexViewMixin

A mixin that adds automatic redirection from the root URL to the first suitable view in a viewset.

class MyViewset(IndexViewMixin, Viewset):
    app_name = "myapp"
    
    # The index path will be auto-created to redirect to the first suitable URL
    home_path = path("home/", HomeView.as_view(), name="home")
    about_path = path("about/", AboutView.as_view(), name="about")

Usage Examples

Basic Viewset

from django.views.generic import TemplateView
from django.urls import path
from material.urls import Viewset

class UserViewset(Viewset):
    app_name = "users"
    
    list_path = path("", UserListView.as_view(), name="list")
    detail_path = path("/", UserDetailView.as_view(), name="detail")
    create_path = path("new/", UserCreateView.as_view(), name="create")
    update_path = path("/edit/", UserUpdateView.as_view(), name="update")
    delete_path = path("/delete/", UserDeleteView.as_view(), name="delete")

Nested Viewsets

from material.urls import Viewset, route

class PostViewset(Viewset):
    app_name = "posts"
    # Post URL patterns...

class CommentViewset(Viewset):
    app_name = "comments"
    # Comment URL patterns...

class BlogViewset(Viewset):
    app_name = "blog"
    
    # Main blog URLs
    home_path = path("", BlogHomeView.as_view(), name="home")
    
    # Nested viewsets
    posts_path = route("posts/", PostViewset())
    comments_path = route("comments/", CommentViewset())

Site and Application Structure

from django.views.generic import TemplateView
from django.urls import path
from material.urls import route
from material.urls.sites import Site, Application, AppMenuMixin

# Define a model viewset that will be part of an application
class ProductViewset(AppMenuMixin, Viewset):
    title = "Products"
    icon = "inventory_2"
    
    list_path = path("", ProductListView.as_view(), name="list")
    detail_path = path("/", ProductDetailView.as_view(), name="detail")
    
    # Get URL for a product object
    def get_object_url(self, request, obj):
        return self.reverse("detail", args=[obj.pk])

# Define an application
class ShopApplication(Application):
    title = "Online Shop"
    icon = "shopping_cart" 
    permission = "shop.view_shop"  # Permission required to access this app
    
    # Direct URL patterns
    dashboard_path = path("", DashboardView.as_view(), name="dashboard")
    settings_path = path("settings/", SettingsView.as_view(), name="settings")
    
    # Add the product viewset
    products_path = route("products/", ProductViewset())

# Define another application
class BlogApplication(Application):
    title = "Blog"
    icon = "article"
    
    post_list_path = path("", PostListView.as_view(), name="post_list")
    post_detail_path = path("/", PostDetailView.as_view(), name="post_detail")

# Create the main site
class ProjectSite(Site):
    title = "My Project"
    primary_color = "indigo"
    secondary_color = "teal"
    
    # Direct URL patterns 
    home_path = path("", HomeView.as_view(), name="home")
    about_path = path("about/", AboutView.as_view(), name="about")
    
    # Add applications
    shop_path = route("shop/", ShopApplication())
    blog_path = route("blog/", BlogApplication())

# Use in your main urls.py
site = ProjectSite()
urlpatterns = [
    path("", site.urls)
]

Model URL Resolution

# Using the site structure from the previous example

# In a view or template context processor
def get_model_urls(request):
    # Get a product instance
    product = Product.objects.get(pk=1)
    
    # Get the URL for this product using the site's get_absolute_url method
    product_url = site.get_absolute_url(request, product)
    # Result: /shop/products/1/
    
    # This works for any model that has a viewset with get_object_url method
    # registered in any application in the site
    
    return {
        'product_url': product_url
    }

Using reverse()

# URL structure from previous example
site = ProjectSite()
urlpatterns = [
    path("", site.urls)
]

# In a view
def some_view(request):
    # Get URL to site home
    home_url = site.reverse("home")  # /
    
    # Get URL to shop dashboard
    shop_url = site.shop_path.viewset.reverse("dashboard")  # /shop/
    
    # Get URL to products list
    products_url = site.shop_path.viewset.products_path.viewset.reverse("list")  # /shop/products/
    
    # Get URL to a specific product
    product_url = site.shop_path.viewset.products_path.viewset.reverse("detail", args=[1])  # /shop/products/1/

Inheritance

class BaseAPIViewset(Viewset):
    list_path = path("", ListView.as_view(), name="list")
    detail_path = path("/", DetailView.as_view(), name="detail")
    create_path = path("create/", CreateView.as_view(), name="create")

class UserAPIViewset(BaseAPIViewset):
    app_name = "users"
    # Override specific paths or add new ones
    detail_path = path("/", UserDetailView.as_view(), name="detail")
    profile_path = path("/profile/", ProfileView.as_view(), name="profile")

Registering Applications Dynamically

# Create a main site
site = Site(title="My Dynamic Site")

# Define an application class
class AnalyticsApplication(Application):
    title = "Analytics"
    icon = "analytics"
    
    dashboard_path = path("", AnalyticsDashboardView.as_view(), name="dashboard")
    reports_path = path("reports/", ReportsView.as_view(), name="reports")

# Register the application with the site
site.register(AnalyticsApplication)

# The app is now accessible at /analytics/
# with automatic namespace 'analytics'

Best Practices

General Guidelines

  • tips_and_updates
    Consistent Naming

    Use consistent naming for URL attributes, ending with _path.

  • tips_and_updates
    Organize by Resource

    Create separate viewsets for different resources or sections of your application.

  • tips_and_updates
    Use IndexViewMixin

    Use IndexViewMixin for viewsets where automatic redirection makes sense.

  • tips_and_updates
    Use reverse() Method

    Prefer the viewset's reverse() method over Django's reverse() for better maintainability.

  • tips_and_updates
    Base Viewsets

    Create base viewsets for common URL patterns to promote code reuse.

Site & Application Tips

  • tips_and_updates
    Structure Hierarchically

    Use Site → Application → Viewset hierarchy for complex projects with multiple sections.

  • tips_and_updates
    Consistent Icons

    Choose appropriate Material Icons for Site and Application classes to improve UX in menus.

  • tips_and_updates
    Use AppMenuMixin

    Implement AppMenuMixin for any viewset that should appear in application menus.

  • tips_and_updates
    Model URLs

    Implement get_object_url method in viewsets with models to enable get_absolute_url functionality.

  • tips_and_updates
    Permission Control

    Use the permission attribute in Applications and Sites for coarse-grained access control.

  • tips_and_updates
    Theming

    Set primary_color and secondary_color in Site class for consistent theming across your application.

Recommended Project Structure

For medium to large projects, consider organizing your URL routing as follows:

# project/urls.py
from django.urls import path
from project.site import site

urlpatterns = [
    path('', site.urls),
]

# project/site.py
from material.urls.sites import Site
from material.urls import route

from project.apps.dashboard.urls import DashboardApplication
from project.apps.users.urls import UserApplication
from project.apps.products.urls import ProductApplication

class ProjectSite(Site):
    title = "My Project"
    primary_color = "indigo"
    secondary_color = "teal"
    
    # Register applications with explicit routes
    dashboard_path = route("", DashboardApplication())
    users_path = route("users/", UserApplication())
    products_path = route("products/", ProductApplication())

# Create the site instance
site = ProjectSite()

# For dynamic registration:
# from project.apps.billing.urls import BillingApplication
# site.register(BillingApplication)