--- tags: Django, hack --- # Django Dynamic URLs Have you ever considered to create dynamic urls in Django? Not the url parameters but the ones which are gernerated according to data from a database or a file. ## Concepts Normally, we create an url path in `urls.py` and map each url to a view function or class: ```python path('demo', app.demo, related_name="demo") path('demo_class', app.DemoClass.as_view(), related_name="demo_class") ``` The path function needs a url string, a view function and other parameters. The point is how do we make the url string and the view function dynamic? ## Dynamic Import The module `imorptlib` offers you to import module by moudle's name. ```python module = importlib.import_module('sys') # <module 'sys' (built-in)> ``` As you can see, the module's name is a string, that means we have more flexibilty to get the modules we want. Import the views through this method would be like: ```python view_module = importlib.import_module('%s.views' % app_name) ``` ## Get The View Next step, we need to get the view from the view_module. A view is an attribute of the view_module, you can see the attribute listed by built-in function `dir()`. ```python dir(view_module) ``` We use the built-in function `getattr()` to get the view. ```python view = getattr(view_module, 'myView') ``` ## Class Based View or Function Based View We have to decide the view is a CBV or a FBV. The biggest difference between these two types of view is, CBV needs to call out `as_view()` function. It means we have to find out wether the class is a class or not: ```python view_function = view.as_view() if inspect.isclass(view) else view ``` ## Return For the case of Django build-in path method `include`: ```python include('app.urls') #(<module 'app.urls' from 'E:\\myproject\\app\\urls.py'>, None, None) ``` Last two parameters are **app_name** and **namesapce**. That means we should add these two parameters when returning the patterns. All in all, ```python def dynamic_urls(programs): urlpatters = [] for program in programs: module_name, view_name = program url = '%s/%s' % (module_name, view_name) # depends on the rule you use module = importlib.import_module('%s.views' % module_name) # dynamic import view = getattr(module, view_name, None) if view: view = view.as_view() if inspect.isclass(view) else view urlpatterns.append( path(url, view) ) return urlpatterns, None, None dynamic_urls(programs) # ([<URLPattern 'app/viewa'>, <URLPattern 'app/viewb'>, # <URLPattern 'common/viewc'>, None, None) ``` Then you can do something like this in your upper level urls.py: ```python programs = ( ('app', 'viewa'), ('app', 'viewb'), ('common', 'viewc'), ) path('demo/', dynamic_urls(programs)) ``` As you see, you can let programs comes from database or other data srouces. ;-)