Package: django-router
Django RouterYou have a data and you need to provide some CRUD functionality for it quickly. What do you do?Create modelAdd some views????PROFIT!Right? Right! Done! And nothing works! Why?URLS.PY!!! You always forget this ones? I have a solution!Maintaining Django'surls.pycan become really annoying when you have a lot of apps with dozens urls in each. Other frameworks deal with it in elegant ways, like Flask's@app.routedecorator. This project brings same concept to Django by adding@routerdecorator functions.CompatibilityThis project is automatically tested with Python 3.7, 3.8, 3.9, 3.10 and Django 2.2, 3.1, 3.2, 4.0, 4.1. Latest version for each release. Compatibility with earlier versions of Python or Django(starting from 2.0) is possible, but not guaranteed.InstallationPackage is hosted inpypi.orgthus you can use any tool that works with it to install the package:pip install django-routerpoetry add django-routerAdddjango_routerto yourINSTALLED_APPS# superduperproject/settings.pyINSTALLED_APPS=[..."django_router",...]Modify projecturls.py(the top one)# superduperproject/urls.pyfromdjango_routerimportrouter# the only time you need to modify any `urls.py`urlpatterns=router.urlpatterns# or with existing onesurlpatterns=[...]+router.urlpatternsConceptTo easily understand all the auto naming concept of the app take a look at testing project within the repo.UsageJust use decorator in your apps'views.py. Django Router usesautodiscoveryfeature, so make sure views you're interested in are either insideviews.pyor get imported into it.# employees/views.pyfromdjango_routerimportrouterfromemployees.modelsimportEmployeefromdjango.shortcutsimportrenderfromdjango.views.generic.editimportCreateView# Works with function based views# Resulting url will be `/employees/employee_list/`@router.path()defemployee_list(request):employees=Employee.objects.all()returnrender(request,'employee_list.html',{'employees':employees})# As well as with class based views# Resulting url will be `/employees/employee_create/`@router.path()defEmployeeCreate(CreateView):model=EmployeeAnd that's it! No more need to deal with lengthyurls.py!How it worksRouter has two functionspathandre_pathwhich work exactly the same asdjango.urlsfunctions you already know. Except that you don't even need to specifyurlorname.View module path is used to determine the resulting URL prefix. So URL for views inemployees/views.pyapp will start with/employees/...,employees/manage/views.py-/employees/manage/...URL etc.Also first module will be used as a namespace for reversereverse('employees:employee_list')NOTICE: nested namespaces are not supported for now.App has some functionality builtin for automaticpatternandnamegeneration.For FBVs if no name is provided function name will be used, camel case will be turned into snake case:# same as path('import_employees/', import_employees, name='import_employees')@router.path()defimport_employees(request):...# same as path('import_employees/', ImportEmployees.as_view(), name='import_employees')@router.path()classImportEmployees(View):...For generic Django views(CreateView,UpdateView,ListView,DetailView,DeleteView) there's some builtin autonaming behavior which tries to be logical.@route.path()classNewEmployeeView(CreateView):model=Employee# is same aspath('employee/create/',NewEmployeeView.as_view(),name='employee_create')Of course you can specify path and name as usual:@router.path('im_emp/',name='employees_import')defimport_employees(request):...SettingsSettings for the project are mostly to control autonaming behavior.
These are default settings for the projectROUTER_SETTINGS={"SIMPLE_AUTO_NAMING":False,"WORDS_SEPARATOR":"_","MODEL_NAMES_MONOLITHIC":True,"DJANGO_ADMIN_LIKE_NAMES":False,"MODULE_PATH_MAP":False}SIMPLE_AUTO_NAMING: if set to true all other settings are ignored, name and url are composed from view name,CamelCaseturned tosnake_case:"test_app.views.SimpleCbv" -> ["/test_app/simple_cbv/", "test_app:simple_cbv"],
"test_app.views.simple_fbv" -> ["/test_app/simple_fbv/", "test_app:simple_fbv"],WORDS_SEPARATOR: a separator char that'll be used during camel to snake case conversion in view names:@router.path()classEmployeeList(ListView):model=EmployeeWORDS_SEPARATOR = "_"path('employee_list/', EmployeeList.as_view(), name='employee_list')WORDS_SEPARATOR = "-"path('employee_list/', EmployeeList.as_view(), name='employee-list')MODEL_NAMES_MONOLITHIC: only works whenMODEL_BASED_PATTERNS = True, control whether separator is used for model names consisting of multiple words@router.path()classEmployeeAddressList(ListView):model=EmployeeAddressMODEL_NAMES_MONOLITHIC = Truepath('employeeaddress/', EmployeesAddressList.as_view(), name='employeeaddress_list')MODEL_NAMES_MONOLITHIC = Falsepath('employee_address/', EmployeesAddressList.as_view(), name='employee_address_list')DJANGO_ADMIN_LIKE_NAMES: if true uses strings like in Django admin for view names and pathsListView: changelistUpdateView: changeCreateView: add@router.path()classEmployeeCreate(CreateView):model=Employeepath('employee/add/', EmployeeCreate.as_view(), name='employee_add')MODULE_PATH_MAP: By default router uses view module path to generate resulting url:students.views.StudentUpdateis split into three parts:students: top level app name, will be used as a prefix for all views insidestudent.viewsviews: name of the module containing views, skipped during path name generationStudentList: view name, turned into a last part of the url depending on previous settings
So resulting url for the view may look like this/students/<int:pk>/update/However you may have a view that has following module path:companies.departments.views.DepartmentUpdate, by default resulting url will look like this:/companies/departments/<int:pk>/update/If you want to avoid this and skip everything between app name and last module name set this settings toFalse.Management commandspython manage.py router_list- to see list of all available routes created by the router.python manage.py router_urls- to see list of all available routes as if they're inurls.py