On this episode, we discuss Django’s front door, URLs. We talk about what URLs are, how to build them in Django, and the functions Django provides to work with URLs.
Listen at djangoriffs.com.
What’s a URL?
A URL is a Uniform Resource Locator. It is the full address that goes into a browser.
Here are the parts:
- Domain name:
- Top Level Domain (TLD),
- Path or route,
- Top Level Domain (TLD),
Every route for Django to handle goes into a URL configuration, URLconf for short and in the documentation.
- The main URLconf is defined by the
- Set to the
project/urls.pyfile by the
What is a URLconf? A Python module with a special list in it.
Open the file and find
urlpatterns list at module level scope.
This list is the rules that Django will follow
to route user’s to your code.
- Each type of route will have a
pathrule in the list.
- Django will match from top to bottom.
- When matching, hand off to your code that you’ll define in views.
Here’s an example URLconf.
# project/urls.py from django.urls import path from application import views urlpatterns = [ path("", views.home), path("about/", views.about), ]
- Empty route matches
about/does a literal match to
- Django URLs end with a slash as a design choice.
This is controlled by the
path is the key function for defining individual routes.
The first parameter is the route string.
Routes are more than strings only.
They can contain converters.
A converter looks like:
A converter’s job is to extract information
from a URL.
This would pull out an integer
and provide a 2020 value
to the view code.
In the following code,
the first ordering will never call
because Django will stop as soon as it finds a match.
path("blog/<int:year>/", views.blog_by_year), path("blog/2020/", views.blog_for_twenty_twenty), # vs. path("blog/2020/", views.blog_for_twenty_twenty), path("blog/<int:year>/", views.blog_by_year),
A view is code that takes an
HttpRequest and returns an
# application/views.py from django.http import HttpResponse def blog_by_year(request, year): # ... some code to handle the year return HttpResponse('some response')
This view function pairs with the converter example above.
The converter passes the extracted
to the view.
Django did all the hard work
of parsing the year for us!
More complicated URLs can be represented
which gives the full power
of Python’s regular expression engine.
Check out URLs Lead The Way article
to learn more.
Django’s tool for grouping is the
Let’s think about a website devoted to some fantasy adventure.
# project/urls.py from django.urls import path from heroes import views as heroes_views urlpatterns = [ path("heroes/", heroes_views.index), path("heroes/<int:hero_id>/", heroes_views.hero_detail), ]
Project has to know the details of the views for
That’s not cool.
Here’s an alternate version
# project/urls.py from django.urls import include, path urlpatterns = [ path("heroes/", include("heroes.urls")), ]
# heroes/urls.py from django.urls import path from . import views urlpatterns = [ path("", views.index), path("<int:hero_id>/", views.hero_detail), ]
The URL configurations function like a tree. Lower level configurations do not need to handle earlier parts of the route.
How can we reference URLs in code?
We could hardcode a
What if we change to
That could be a lot of editing.
Django lets us name URLs. This is a layer of indirection.
# heroes/urls.py from django.urls import path from . import views urlpatterns = [ path("", views.index, name="index"), ]
To use this, we need a new tool, the
>>> from django.urls import reverse >>> reverse("index") == "/heroes/" True
There’s a problem with
index as the name of the URL.
What if another view in a different app (like villains) also wanted to use the name
There’s a conflict. Who wins? The name
index becomes ambiguous.
How can we get around that? We create a namespace!
$ python >>> import this The Zen of Python, by Tim Peters ... Namespaces are one honking great idea -- let's do more of those!
We could do a manual namespace
by renaming to
Plenty of Django developers do this!
But Django gives us another tool.
# heroes/urls.py from django.urls import path from . import views app_name = "heroes" urlpatterns = [ path("", views.index, name="index"), ]
app_name to give the app a namespace.
We need a small tweak to how we use
>>> from django.urls import reverse >>> reverse("heroes:index") == "/heroes/" True
In the next episode, we’ll look at views, the different kinds of views, and tools to help build them.
Please rate or review on iTunes, Spotify, or from wherever you listen to podcasts. Your rating will help others discover the podcast, and I would be very grateful.
Django Riffs is supported by listeners like you. If you can contribute financially to cover hosting and production costs, please check out my Patreon page to see how you can help out.
Learn more about Python!
You can join my newsletter along with over 800 other developers and get access to useful topics to help you learn more about Python and software development.
I’ll get you started with my Pythonic code email course. I hope you'll join up!