Slides from my presentation at MelbDjango in January 2018 on the changes to URLs in Django 2.0.
Django 2.0
- Released December, 2017
- Major features:
- Only supports Python 3.4 and above
- Mobile-friendly admin interface
- Simplified URL routing syntax
The old way
from django.conf.urls import url
urlpatterns = [
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
]
- Required users to understand regular expressions
- Passes URL parameters as strings to your views
The new way
from django.urls import path
urlpatterns = [
path('articles/<int:year>/', views.year_archive)
]
- Simpler for new users (no more regex!)
- Handles coercion into the designated type
- Can be extended with ... functions
And you can still regex
from django.urls import re_path
urlpatterns = [
# support date paths: /date/2018-01-18
re_path(r'^date/(?P<year>[0-9]{4})-(?P<month>[0-9]{2})-(?P<day>[0-9]{2})$', views.day_archive)
]
- You can use
django.urls.re_path
to add regex-based URLs - (you can also just keep using the old
url
function)
The built in converters
int
: Matches zero or any positive integer. Returns an int.
Old:
url(r'^posts/(?P<pk>[0-9]+)/$', views.post)
New:
path('posts/<int:pk>/', views.post)
The built in converters
str
: Matches any non-empty string, excluding the path separator, '/'
Old:
url(r'^define/(?P<word>[^/]+)/$', views.define)
New:
path('posts/<str:word>/', views.define)
or
path('posts/<word>/', views.define)
The built in converters
uuid
: Matches a formatted UUID.
Old:
url(r'^(?P<pk>\b[0-9a-f]{8}\b(-\b[0-9a-f]{4}\b){3}-\b[0-9a-f]{12}\b)$', views.post)
New:
path('<uuid:pk>/', views.post)
The built in converters
slug
: Matches slugs compatible with SlugField
Old:
url(r'^posts/(?P<post_slug>[-\w]+)/$', views.post)
New:
path('posts/<slug:post_slug>/', views.post)
The built in converters
path
: Matches any non-empty string, including the path separator, '/'.
Old:
url(r'^url/(?P<url>.+)/$', views.url_info)
New:
path('url/<path:url>', views.url_info)
Adding your own converter
-
Register custom converters with
django.urls.register_converter
- The documentation suggests doing this in your
urls.py
- The documentation suggests doing this in your
-
register_converter
takes two arguments:- A Converter
- The "type name" used in the URL
isodate converter
import datetime
from django.urls import register_converter
class IsoDateConverter:
regex = '\d{4}-\d{2}-\d{2}'
def to_python(self, value):
return datetime.datetime.strptime(value, '%Y-%m-%d').date()
def to_url(self, value):
return str(value)
register_converter(IsoDateConverter, 'isodate')
Custom conversion functions
- The result of
to_python
will be passed to your view - If an exception is raised, the next URL pattern will be used
- Simple to test:
def test_isodate(self):
response = self.client.get('/url/2018-01-18/').json()
self.assertEqual('isodate', response['url_name'])
That's it!
- Follow me on Twitter: @sesh
- Talk will be on https://brntn.me
- I work at Thoughtworks now (it's great)
Resources
- https://docs.djangoproject.com/en/2.0/releases/2.0/
- https://docs.djangoproject.com/en/2.0/topics/http/urls/
- https://docs.djangoproject.com/en/2.0/topics/http/urls/#how-django-processes-a-request
- https://docs.djangoproject.com/en/2.0/ref/urls/#django.urls.path