Url consolidation and modularization
By default, Django looks up url
definitions in the urls.py
file inside a project's
main directory -- it's worth mentioning this is on account of the
ROOT_URLCONF
variable in settings.py
.
However, once a project grows beyond a couple of urls, it can
become difficult to manage them inside this single file. For
example, look at the the urls.py
file illustrated in
listing 2-10.
Listing 2-10. Django urls.py with no url consolidation
from django.conf.urls import url from django.views.generic import TemplateView from coffeehouse.about import views as about_views from coffeehouse.stores import views as stores_views urlpatterns = [ url(r'^$',TemplateView.as_view(template_name='homepage.html')), url(r'^about/',about_views.index), url(r'^about/contact/',about_views.contact), url(r'^stores/',stores_views.index), url(r'^stores/(?P<store_id>\d+)/',stores_views.detail,{'location':'headquarters'}), ]
As you can see in listing 2-10,
there are a couple of urls that have redundant roots --
about/
and stores/
. Grouping these urls
separately can be helpful because it keeps common urls in their own
files and avoids the difficulties of making changes to one big
urls.py
file.
Listing 2-11 shows an updated
version of the urls.py
file in listing 2-11 with the
about/
and stores/
roots are placed in
separate files.
Listing 2-11. Django urls.py with include to consolidate urls
from django.conf.urls import include, url from django.views.generic import TemplateView urlpatterns = [ url(r'^$',TemplateView.as_view(template_name='homepage.html')), url(r'^about/',include('coffeehouse.about.urls')), url(r'^stores/',include('coffeehouse.stores.urls'),{'location':'headquarters'}), ]
Listing 2-11 makes use of the
include
argument to load urls from completely separate
files. In this case, include('coffeehouse.about.urls')
tells Django to load url definitions from the Python module
coffeehouse.about.urls
, which parting from a Django
base directory corresponds to the file route
/coffeehouse/about/urls.py
. In this case, I kept using
the urls.py
file name and placed it under the
corresponding Django about app directory since it deals with
about/
urls. However, you can use any file name or
path you like for url definitions (e.g.
coffeehouse.allmyurl.resturls
to load urls from a file
route /coffeehouse/allmyurls/resturls.py
).
The second include statement in
listing 2-11 works just like the first one, where
include('coffeehouse.stores.urls')
tells Django to
load url definitions from the Python module
coffeehouse.stores.urls
. However, notice this second
statement appends an additional dictionary as a url extra option,
which means all the urls in the include statement will also receive
this extra option.
Listing 2-12 illustrates the
contents of the file /coffeehouse/about/urls.py
linked
via include('coffeehouse.about.urls')
.
Listing 2-12. Django /coffeehouse/about/urls.py loaded via include
from django.conf.urls import url from . import views urlpatterns = [ url(r'^$',views.index), url(r'^contact/$',views.contact), ]
A quick look at listing 2-12 and
you can see the structure is pretty similar to the main
urls.py
file, however, there are some minor
differences. While the url regular expression r'^$'
can look like it matches the home page, it isn't. Because the file
in listing 2-12 is linked via include
in the main
urls.py
file, Django joins the url regular expression
with the parent url regular expression. So the first url in listing
2-12 actually matches /about/
and the second url in
listing 2-12 actually matches /about/contact/
. Also
because the urls.py
file in listing 2-12 is placed
alongside the app's views.py
file, the import
statement uses the relative path from . import views
syntax.
In addition to using the
include
option to reference a separate file with url
definitions, the include
option can also accept url
definitions as a Python list. In essence, this allows you to keep
all url definitions in the main urls.py
file, but give
it more modularity. This approach is illustrated in listing
2-13.
Listing 2-13 Django urls.py with inline include statements
from django.conf.urls import include, url from django.views.generic import TemplateView from coffeehouse.about import views as about_views from coffeehouse.stores import views as stores_views store_patterns = [ url(r'^$',stores_views.index), url(r'^(?P<store_id>\d+)/$',stores_views.detail), ] about_patterns = [ url(r'^$',about_views.index), url(r'^contact/$',about_views.contact), ] urlpatterns = [ url(r'^$',TemplateView.as_view(template_name='homepage.html')), url(r'^about/',include(about_patterns)), url(r'^stores/',include(store_patterns),{'location':'headquarters'}), ]
The outcome of the url patterns
in listing 2-13 is the same as listings 2-11 and 2-12. The
difference is listing 2-13 uses the main urls.py
file
to declare multiple url lists, while listings 2-11 and 2-12 rely on
url lists declared in different files.