URL Auto-Registration

Developer guide for the Enezaframework. Part of the architecture series.

Table of Contents

  1. Overview
  2. @auto_url_register
  3. get_registered_urls
  4. Writing the App's urls.py
  5. Generated URL Reference
  6. Naming and Collisions
  7. Related Guides

Overview

Instead of hand-writing a URL pattern for every CRUD view, decorate the view with @auto_url_register. The decorator records the view in a registry, and the app's urls.py pulls the generated patterns with get_registered_urls(app_name).

sequenceDiagram
    participant Dev as Developer
    participant Dec as auto_url_register
    participant Reg as URL_REGISTRY
    participant URLS as app urls.py
    participant Django

    Dev->>Dec: decorate view class
    Dec->>Reg: append view class
    URLS->>Reg: get_registered_urls(app_name)
    Reg-->>URLS: list of path() patterns
    URLS->>Django: urlpatterns = [*dynamic_urls]
    Django-->>Dev: reverse("app:model_list") works

@auto_url_register

Import and apply it to each view class:

python
from enezaframework.utils import auto_url_register
from enezaframework.views import BaseListView, BaseDetailView, BaseCreateView, BaseDeleteView
from accountpayable.models import VendorTable


@auto_url_register
class VendorTableListView(BaseListView):
    model = VendorTable

    def set_list_fields(self):
        return ["vendorno", "searchname"]

    def set_search_fields(self):
        return ["vendorno", "searchname"]


@auto_url_register
class VendorTableDetailView(BaseDetailView):
    model = VendorTable


@auto_url_register
class VendorTableCreateView(BaseCreateView):
    model = VendorTable


@auto_url_register
class VendorTableDeleteView(BaseDeleteView):
    model = VendorTable

Rules and behavior:

  1. Model-backed views must define a model attribute, otherwise the decorator raises ValueError. Pure View subclasses (such as BaseAction) are exempt.
  2. The decorator appends the class to URL_REGISTRY; it does not create URLs by itself.
  3. The view must expose the view_type attribute expected by get_registered_urls (the base views set this for you: list, detail, create, delete, action, parameter, one_to_one_detail, document_report, and others).
  4. url_name overrides the URL prefix; otherwise the lowercase model name (model._meta.model_name) is used.

get_registered_urls

python
from enezaframework.utils import get_registered_urls

dynamic_urls = get_registered_urls("accountpayable")

Signature: get_registered_urls(app_name="enezaframework").

The function iterates URL_REGISTRY, keeps classes whose module belongs to app_name, and produces a path() for each recognized view_type. Views from other apps are skipped, so each app only receives its own routes.


Writing the App's urls.py

Combine manually defined views with the framework-generated routes.

python
from django.urls import path

from . import views
from enezaframework.utils import get_registered_urls

app_name = "accountpayable"

dynamic_urls = get_registered_urls(app_name)

urlpatterns = [
    # Manually defined views (dashboards, reports, custom endpoints)
    path("dashboard", views.accountpayable_dashboard, name="accountpayable_dashboard"),

    # All auto-registered CRUD routes for this app
    *dynamic_urls,
]
  • Set app_name to the actual app name; it namespaces reverse lookups.
  • Distribute *dynamic_urls into urlpatterns; if you forget, the app will miss every auto-generated CRUD endpoint.
  • Manually defined views are still needed for things the framework does not generate (dashboards, custom reports).

Generated URL Reference

Route shape and URL name depend on the view's view_type. The prefix is url_name if set, otherwise the lowercase model name.

view_type Pattern URL name
list {prefix}/ {prefix}_list
detail {prefix}/<str:pk>/ {prefix}_detail
create {prefix}_create/ {prefix}_create
delete {prefix}_delete/<str:pk>/ {prefix}_delete
parameter {prefix}/ {prefix}_parameter
one_to_one_detail {prefix}/<str:pk>/ {prefix}_detail
action {action_name_title}/<str:pk> {action_name}_action
autocomplete {prefix}_autocomplete/ {prefix}_autocomplete
workflow {prefix}_workflow/<str:pk>/ {prefix}_workflow
document_report {report_name}_report/<str:pk>/ {report_name}_report

Notes:

  • Primary keys are captured as <str:pk> because framework models use UUID primary keys.
  • There is no auto-generated update route. Editing is handled by the detail view; use the detail URL for edit navigation.
  • document_report uses report_name when set, otherwise the model prefix. See docs/Dev/document-report-page-view-developer-guide.md for the report view itself.

Example for a VendorTable model

URL name Path
accountpayable:vendortable_list /vendortable/
accountpayable:vendortable_detail /vendortable/<pk>/
accountpayable:vendortable_create /vendortable_create/
accountpayable:vendortable_delete /vendortable_delete/<pk>/

If the view sets url_name = "vendors", the prefixes become /vendors/, /vendors/<pk>/, /vendors_create/, and /vendors_delete/<pk>/, with URL names vendors_list, and so on.


Naming and Collisions

  • Two views with the same view_type and the same prefix in one app produce colliding URL names. Set url_name on one of them to disambiguate.
  • The prefix for an unset url_name is the model name, not the class name. A VendorTableListView and VendorTableDetailView therefore share the vendortable prefix but differ by suffix.
  • Menu entries must reference the exact generated name (app_name:url_name); see Menu & Navigation Configuration.
  • report_name on a document report view lets one model expose multiple distinct report URLs.