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_updatesConsistent Naming
Use consistent naming for URL attributes, ending with
_path
. -
tips_and_updatesOrganize by Resource
Create separate viewsets for different resources or sections of your application.
-
tips_and_updatesUse IndexViewMixin
Use IndexViewMixin for viewsets where automatic redirection makes sense.
-
tips_and_updatesUse reverse() Method
Prefer the viewset's reverse() method over Django's reverse() for better maintainability.
-
tips_and_updatesBase Viewsets
Create base viewsets for common URL patterns to promote code reuse.
Site & Application Tips
-
tips_and_updatesStructure Hierarchically
Use Site → Application → Viewset hierarchy for complex projects with multiple sections.
-
tips_and_updatesConsistent Icons
Choose appropriate Material Icons for Site and Application classes to improve UX in menus.
-
tips_and_updatesUse AppMenuMixin
Implement AppMenuMixin for any viewset that should appear in application menus.
-
tips_and_updatesModel URLs
Implement
get_object_url
method in viewsets with models to enableget_absolute_url
functionality. -
tips_and_updatesPermission Control
Use the
permission
attribute in Applications and Sites for coarse-grained access control. -
tips_and_updatesTheming
Set
primary_color
andsecondary_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)