summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/internals/deprecation.txt9
-rw-r--r--docs/intro/overview.txt29
-rw-r--r--docs/intro/reusable-apps.txt2
-rw-r--r--docs/intro/tutorial01.txt91
-rw-r--r--docs/intro/tutorial03.txt62
-rw-r--r--docs/intro/tutorial04.txt16
-rw-r--r--docs/ref/checks.txt16
-rw-r--r--docs/ref/class-based-views/base.txt16
-rw-r--r--docs/ref/class-based-views/generic-date-based.txt64
-rw-r--r--docs/ref/class-based-views/generic-display.txt8
-rw-r--r--docs/ref/class-based-views/index.txt2
-rw-r--r--docs/ref/class-based-views/mixins-multiple-object.txt2
-rw-r--r--docs/ref/contrib/admin/admindocs.txt4
-rw-r--r--docs/ref/contrib/admin/index.txt44
-rw-r--r--docs/ref/contrib/flatpages.txt14
-rw-r--r--docs/ref/contrib/gis/tutorial.txt4
-rw-r--r--docs/ref/contrib/sitemaps.txt46
-rw-r--r--docs/ref/contrib/staticfiles.txt3
-rw-r--r--docs/ref/contrib/syndication.txt12
-rw-r--r--docs/ref/templates/builtins.txt18
-rw-r--r--docs/ref/urlresolvers.txt2
-rw-r--r--docs/ref/urls.txt118
-rw-r--r--docs/ref/utils.txt4
-rw-r--r--docs/ref/views.txt3
-rw-r--r--docs/releases/1.4.txt5
-rw-r--r--docs/releases/1.9.txt6
-rw-r--r--docs/releases/2.0.txt26
-rw-r--r--docs/topics/auth/default.txt12
-rw-r--r--docs/topics/cache.txt6
-rw-r--r--docs/topics/class-based-views/generic-display.txt14
-rw-r--r--docs/topics/class-based-views/generic-editing.txt8
-rw-r--r--docs/topics/class-based-views/index.txt12
-rw-r--r--docs/topics/class-based-views/intro.txt10
-rw-r--r--docs/topics/class-based-views/mixins.txt4
-rw-r--r--docs/topics/http/urls.txt434
-rw-r--r--docs/topics/i18n/translation.txt52
36 files changed, 642 insertions, 536 deletions
diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt
index 94c470cbc1..12859b182e 100644
--- a/docs/internals/deprecation.txt
+++ b/docs/internals/deprecation.txt
@@ -147,7 +147,7 @@ details on these changes.
``django.utils.feedgenerator.RssFeed`` will be removed in favor of
``content_type``.
-* The ``app_name`` argument to :func:`~django.conf.urls.include()` will be
+* The ``app_name`` argument to ``django.conf.urls.include()`` will be
removed.
* Support for passing a 3-tuple as the first argument to ``include()`` will
@@ -786,10 +786,9 @@ details on these changes.
``django.contrib.gis.utils`` will be removed.
* ``django.conf.urls.defaults`` will be removed. The functions
- :func:`~django.conf.urls.include`, ``patterns()`` and
- :func:`~django.conf.urls.url` plus :data:`~django.conf.urls.handler404`,
- :data:`~django.conf.urls.handler500`, are now available through
- :mod:`django.conf.urls` .
+ ``include()``, ``patterns()``, and ``url()``, plus
+ :data:`~django.conf.urls.handler404` and :data:`~django.conf.urls.handler500`
+ are now available through ``django.conf.urls``.
* The functions ``setup_environ()`` and ``execute_manager()`` will be removed
from :mod:`django.core.management`. This also means that the old (pre-1.4)
diff --git a/docs/intro/overview.txt b/docs/intro/overview.txt
index b47f004d30..203e501054 100644
--- a/docs/intro/overview.txt
+++ b/docs/intro/overview.txt
@@ -191,31 +191,30 @@ example above:
.. snippet::
:filename: mysite/news/urls.py
- from django.conf.urls import url
+ from django.urls import path
from . import views
urlpatterns = [
- url(r'^articles/([0-9]{4})/$', views.year_archive),
- url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
- url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
+ path('articles/<int:year>/', views.year_archive),
+ path('articles/<int:year>/<int:month>/', views.month_archive),
+ path('articles/<int:year>/<int:month>/<int:pk>/', views.article_detail),
]
-The code above maps URLs, as simple :ref:`regular expressions <regex-howto>`,
-to the location of Python callback functions ("views"). The regular expressions
-use parenthesis to "capture" values from the URLs. When a user requests a page,
-Django runs through each pattern, in order, and stops at the first one that
-matches the requested URL. (If none of them matches, Django calls a
-special-case 404 view.) This is blazingly fast, because the regular expressions
-are compiled at load time.
+The code above maps URL paths to Python callback functions ("views"). The path
+strings use parameter tags to "capture" values from the URLs. When a user
+requests a page, Django runs through each path, in order, and stops at the
+first one that matches the requested URL. (If none of them matches, Django
+calls a special-case 404 view.) This is blazingly fast, because the paths are
+compiled into regular expressions at load time.
-Once one of the regexes matches, Django calls the given view, which is a Python
-function. Each view gets passed a request object -- which contains request
-metadata -- and the values captured in the regex.
+Once one of the URL patterns matches, Django calls the given view, which is a
+Python function. Each view gets passed a request object -- which contains
+request metadata -- and the values captured in the pattern.
For example, if a user requested the URL "/articles/2005/05/39323/", Django
would call the function ``news.views.article_detail(request,
-'2005', '05', '39323')``.
+year=2005, month=5, pk=39323)``.
Write your views
================
diff --git a/docs/intro/reusable-apps.txt b/docs/intro/reusable-apps.txt
index 90d807fd06..5a5038f3a0 100644
--- a/docs/intro/reusable-apps.txt
+++ b/docs/intro/reusable-apps.txt
@@ -165,7 +165,7 @@ this. For a small app like polls, this process isn't too difficult.
2. Include the polls URLconf in your project urls.py like this::
- url(r'^polls/', include('polls.urls')),
+ path('polls/', include('polls.urls')),
3. Run `python manage.py migrate` to create the polls models.
diff --git a/docs/intro/tutorial01.txt b/docs/intro/tutorial01.txt
index aef9a1e66f..fca0cca25b 100644
--- a/docs/intro/tutorial01.txt
+++ b/docs/intro/tutorial01.txt
@@ -274,55 +274,45 @@ In the ``polls/urls.py`` file include the following code:
.. snippet::
:filename: polls/urls.py
- from django.conf.urls import url
+ from django.urls import path
from . import views
urlpatterns = [
- url(r'^$', views.index, name='index'),
+ path('', views.index, name='index'),
]
The next step is to point the root URLconf at the ``polls.urls`` module. In
-``mysite/urls.py``, add an import for ``django.conf.urls.include`` and insert
-an :func:`~django.conf.urls.include` in the ``urlpatterns`` list, so you have:
+``mysite/urls.py``, add an import for ``django.urls.include`` and insert an
+:func:`~django.urls.include` in the ``urlpatterns`` list, so you have:
.. snippet::
:filename: mysite/urls.py
- from django.conf.urls import include, url
+ from django.urls import include, path
from django.contrib import admin
urlpatterns = [
- url(r'^polls/', include('polls.urls')),
- url(r'^admin/', admin.site.urls),
+ path('polls/', include('polls.urls')),
+ path('admin/', admin.site.urls),
]
-The :func:`~django.conf.urls.include` function allows referencing other
-URLconfs. Note that the regular expressions for the
-:func:`~django.conf.urls.include` function doesn't have a ``$`` (end-of-string
-match character) but rather a trailing slash. Whenever Django encounters
-:func:`~django.conf.urls.include`, it chops off whatever part of the URL
-matched up to that point and sends the remaining string to the included URLconf
-for further processing.
+The :func:`~django.urls.include` function allows referencing other URLconfs.
+Whenever Django encounters :func:`~django.urls.include`, it chops off whatever
+part of the URL matched up to that point and sends the remaining string to the
+included URLconf for further processing.
-The idea behind :func:`~django.conf.urls.include` is to make it easy to
+The idea behind :func:`~django.urls.include` is to make it easy to
plug-and-play URLs. Since polls are in their own URLconf
(``polls/urls.py``), they can be placed under "/polls/", or under
"/fun_polls/", or under "/content/polls/", or any other path root, and the
app will still work.
-.. admonition:: When to use :func:`~django.conf.urls.include()`
+.. admonition:: When to use :func:`~django.urls.include()`
You should always use ``include()`` when you include other URL patterns.
``admin.site.urls`` is the only exception to this.
-.. admonition:: Doesn't match what you see?
-
- If you're seeing ``include(admin.site.urls)`` instead of just
- ``admin.site.urls``, you're probably using a version of Django that
- doesn't match this tutorial version. You'll want to either switch to the
- older tutorial or the newer Django version.
-
You have now wired an ``index`` view into the URLconf. Lets verify it's
working, run the following command:
@@ -334,56 +324,39 @@ Go to http://localhost:8000/polls/ in your browser, and you should see the
text "*Hello, world. You're at the polls index.*", which you defined in the
``index`` view.
-The :func:`~django.conf.urls.url` function is passed four arguments, two
-required: ``regex`` and ``view``, and two optional: ``kwargs``, and ``name``.
+The :func:`~django.urls.path` function is passed four arguments, two required:
+``route`` and ``view``, and two optional: ``kwargs``, and ``name``.
At this point, it's worth reviewing what these arguments are for.
-:func:`~django.conf.urls.url` argument: regex
+:func:`~django.urls.path` argument: ``route``
---------------------------------------------
-The term "regex" is a commonly used short form meaning "regular expression",
-which is a syntax for matching patterns in strings, or in this case, url
-patterns. Django starts at the first regular expression and makes its way down
-the list, comparing the requested URL against each regular expression until it
-finds one that matches.
-
-Note that these regular expressions do not search GET and POST parameters, or
-the domain name. For example, in a request to
-``https://www.example.com/myapp/``, the URLconf will look for ``myapp/``. In a
-request to ``https://www.example.com/myapp/?page=3``, the URLconf will also
-look for ``myapp/``.
-
-If you need help with regular expressions, see `Wikipedia's entry`_ and the
-documentation of the :mod:`re` module. Also, the O'Reilly book "Mastering
-Regular Expressions" by Jeffrey Friedl is fantastic. In practice, however,
-you don't need to be an expert on regular expressions, as you really only need
-to know how to capture simple patterns. In fact, complex regexes can have poor
-lookup performance, so you probably shouldn't rely on the full power of regexes.
+``route`` is a string that contains a URL pattern. When processing a request,
+Django starts at the first pattern in ``urlpatterns`` and makes its way down
+the list, comparing the requested URL against each pattern until it finds one
+that matches.
-Finally, a performance note: these regular expressions are compiled the first
-time the URLconf module is loaded. They're super fast (as long as the lookups
-aren't too complex as noted above).
+Patterns don't search GET and POST parameters, or the domain name. For example,
+in a request to ``https://www.example.com/myapp/``, the URLconf will look for
+``myapp/``. In a request to ``https://www.example.com/myapp/?page=3``, the
+URLconf will also look for ``myapp/``.
-.. _Wikipedia's entry: https://en.wikipedia.org/wiki/Regular_expression
-
-:func:`~django.conf.urls.url` argument: view
+:func:`~django.urls.path` argument: ``view``
--------------------------------------------
-When Django finds a regular expression match, Django calls the specified view
-function, with an :class:`~django.http.HttpRequest` object as the first
-argument and any “captured” values from the regular expression as other
-arguments. If the regex uses simple captures, values are passed as positional
-arguments; if it uses named captures, values are passed as keyword arguments.
-We'll give an example of this in a bit.
+When Django finds a matching pattern, it calls the specified view function with
+an :class:`~django.http.HttpRequest` object as the first argument and any
+"captured" values from the route as keyword arguments. We'll give an example
+of this in a bit.
-:func:`~django.conf.urls.url` argument: kwargs
+:func:`~django.urls.path` argument: ``kwargs``
----------------------------------------------
Arbitrary keyword arguments can be passed in a dictionary to the target view. We
aren't going to use this feature of Django in the tutorial.
-:func:`~django.conf.urls.url` argument: name
----------------------------------------------
+:func:`~django.urls.path` argument: ``name``
+--------------------------------------------
Naming your URL lets you refer to it unambiguously from elsewhere in Django,
especially from within templates. This powerful feature allows you to make
diff --git a/docs/intro/tutorial03.txt b/docs/intro/tutorial03.txt
index 2d1104d3d7..32c0c99fd1 100644
--- a/docs/intro/tutorial03.txt
+++ b/docs/intro/tutorial03.txt
@@ -53,10 +53,10 @@ A URL pattern is simply the general form of a URL - for example:
``/newsarchive/<year>/<month>/``.
To get from a URL to a view, Django uses what are known as 'URLconfs'. A
-URLconf maps URL patterns (described as regular expressions) to views.
+URLconf maps URL patterns to views.
This tutorial provides basic instruction in the use of URLconfs, and you can
-refer to :mod:`django.urls` for more information.
+refer to :doc:`/topics/http/urls` for more information.
Writing more views
==================
@@ -78,24 +78,24 @@ slightly different, because they take an argument:
return HttpResponse("You're voting on question %s." % question_id)
Wire these new views into the ``polls.urls`` module by adding the following
-:func:`~django.conf.urls.url` calls:
+:func:`~django.urls.path` calls:
.. snippet::
:filename: polls/urls.py
- from django.conf.urls import url
+ from django.urls import path
from . import views
urlpatterns = [
# ex: /polls/
- url(r'^$', views.index, name='index'),
+ path('', views.index, name='index'),
# ex: /polls/5/
- url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
+ path('<int:question_id>/', views.detail, name='detail'),
# ex: /polls/5/results/
- url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
+ path('<int:question_id>/results/', views.results, name='results'),
# ex: /polls/5/vote/
- url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
+ path('<int:question_id>/vote/', views.vote, name='vote'),
]
Take a look in your browser, at "/polls/34/". It'll run the ``detail()``
@@ -106,26 +106,24 @@ placeholder results and voting pages.
When somebody requests a page from your website -- say, "/polls/34/", Django
will load the ``mysite.urls`` Python module because it's pointed to by the
:setting:`ROOT_URLCONF` setting. It finds the variable named ``urlpatterns``
-and traverses the regular expressions in order. After finding the match at
-``'^polls/'``, it strips off the matching text (``"polls/"``) and sends the
-remaining text -- ``"34/"`` -- to the 'polls.urls' URLconf for further
-processing. There it matches ``r'^(?P<question_id>[0-9]+)/$'``, resulting in a
-call to the ``detail()`` view like so::
+and traverses the patterns in order. After finding the match at ``'polls/'``,
+it strips off the matching text (``"polls/"``) and sends the remaining text --
+``"34/"`` -- to the 'polls.urls' URLconf for further processing. There it
+matches ``'<int:question_id>/'``, resulting in a call to the ``detail()`` view
+like so::
- detail(request=<HttpRequest object>, question_id='34')
+ detail(request=<HttpRequest object>, question_id=34)
-The ``question_id='34'`` part comes from ``(?P<question_id>[0-9]+)``. Using parentheses
-around a pattern "captures" the text matched by that pattern and sends it as an
-argument to the view function; ``?P<question_id>`` defines the name that will
-be used to identify the matched pattern; and ``[0-9]+`` is a regular expression to
-match a sequence of digits (i.e., a number).
+The ``question_id=34`` part comes from ``<int:question_id>``. Using angle
+brackets "captures" part of the URL and sends it as a keyword argument to the
+view function. The ``:question_id>`` part of the string defines the name that
+will be used to identify the matched pattern, and the ``<int:`` part is a
+converter that determines what patterns should match this part of the URL path.
-Because the URL patterns are regular expressions, there really is no limit on
-what you can do with them. And there's no need to add URL cruft such as
-``.html`` -- unless you want to, in which case you can do something like
-this::
+There's no need to add URL cruft such as ``.html`` -- unless you want to, in
+which case you can do something like this::
- url(r'^polls/latest\.html$', views.index),
+ path('polls/latest.html', views.index),
But, don't do that. It's silly.
@@ -388,7 +386,7 @@ template, the link was partially hardcoded like this:
The problem with this hardcoded, tightly-coupled approach is that it becomes
challenging to change URLs on projects with a lot of templates. However, since
-you defined the name argument in the :func:`~django.conf.urls.url` functions in
+you defined the name argument in the :func:`~django.urls.path` functions in
the ``polls.urls`` module, you can remove a reliance on specific URL paths
defined in your url configurations by using the ``{% url %}`` template tag:
@@ -402,7 +400,7 @@ defined below::
...
# the 'name' value as called by the {% url %} template tag
- url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
+ path('<int:question_id>/', views.detail, name='detail'),
...
If you want to change the URL of the polls detail view to something else,
@@ -411,7 +409,7 @@ template (or templates) you would change it in ``polls/urls.py``::
...
# added the word 'specifics'
- url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
+ path('specifics/<int:question_id>/', views.detail, name='detail'),
...
Namespacing URL names
@@ -430,16 +428,16 @@ file, go ahead and add an ``app_name`` to set the application namespace:
.. snippet::
:filename: polls/urls.py
- from django.conf.urls import url
+ from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
- url(r'^$', views.index, name='index'),
- url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
- url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
- url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
+ path('', views.index, name='index'),
+ path('<int:question_id>/', views.detail, name='detail'),
+ path('<int:question_id>/results/', views.results, name='results'),
+ path('<int:question_id>/vote/', views.vote, name='vote'),
]
Now change your ``polls/index.html`` template from:
diff --git a/docs/intro/tutorial04.txt b/docs/intro/tutorial04.txt
index f320476548..6f685fc402 100644
--- a/docs/intro/tutorial04.txt
+++ b/docs/intro/tutorial04.txt
@@ -61,7 +61,7 @@ created a URLconf for the polls application that includes this line:
.. snippet::
:filename: polls/urls.py
- url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
+ path('<int:question_id>/vote/', views.vote, name='vote'),
We also created a dummy implementation of the ``vote()`` function. Let's
create a real version. Add the following to ``polls/views.py``:
@@ -237,20 +237,20 @@ First, open the ``polls/urls.py`` URLconf and change it like so:
.. snippet::
:filename: polls/urls.py
- from django.conf.urls import url
+ from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
- url(r'^$', views.IndexView.as_view(), name='index'),
- url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
- url(r'^(?P<pk>[0-9]+)/results/$', views.ResultsView.as_view(), name='results'),
- url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
+ path('', views.IndexView.as_view(), name='index'),
+ path('<int:pk>/', views.DetailView.as_view(), name='detail'),
+ path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
+ path('<int:question_id>/vote/', views.vote, name='vote'),
]
-Note that the name of the matched pattern in the regexes of the second and third
-patterns has changed from ``<question_id>`` to ``<pk>``.
+Note that the name of the matched pattern in the path strings of the second and
+third patterns has changed from ``<question_id>`` to ``<pk>``.
Amend views
-----------
diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt
index 0ca1d176f4..45bef40688 100644
--- a/docs/ref/checks.txt
+++ b/docs/ref/checks.txt
@@ -444,18 +444,18 @@ URLs
The following checks are performed on your URL configuration:
* **urls.W001**: Your URL pattern ``<pattern>`` uses
- :func:`~django.conf.urls.include` with a ``regex`` ending with a
- ``$``. Remove the dollar from the ``regex`` to avoid problems
- including URLs.
-* **urls.W002**: Your URL pattern ``<pattern>`` has a ``regex``
- beginning with a ``/``. Remove this slash as it is unnecessary.
- If this pattern is targeted in an :func:`~django.conf.urls.include`, ensure
- the :func:`~django.conf.urls.include` pattern has a trailing ``/``.
+ :func:`~django.urls.include` with a ``route`` ending with a ``$``. Remove the
+ dollar from the ``route`` to avoid problems including URLs.
+* **urls.W002**: Your URL pattern ``<pattern>`` has a ``route`` beginning with
+ a ``/``. Remove this slash as it is unnecessary. If this pattern is targeted
+ in an :func:`~django.urls.include`, ensure the :func:`~django.urls.include`
+ pattern has a trailing ``/``.
* **urls.W003**: Your URL pattern ``<pattern>`` has a ``name``
including a ``:``. Remove the colon, to avoid ambiguous namespace
references.
* **urls.E004**: Your URL pattern ``<pattern>`` is invalid. Ensure that
- ``urlpatterns`` is a list of :func:`~django.conf.urls.url()` instances.
+ ``urlpatterns`` is a list of :func:`~django.urls.path` and/or
+ :func:`~django.urls.re_path` instances.
* **urls.W005**: URL namespace ``<namespace>`` isn't unique. You may not be
able to reverse all URLs in this namespace.
* **urls.E006**: The :setting:`MEDIA_URL`/ :setting:`STATIC_URL` setting must
diff --git a/docs/ref/class-based-views/base.txt b/docs/ref/class-based-views/base.txt
index 6230f1181e..6ef72176c3 100644
--- a/docs/ref/class-based-views/base.txt
+++ b/docs/ref/class-based-views/base.txt
@@ -40,12 +40,12 @@ MRO is an acronym for Method Resolution Order.
**Example urls.py**::
- from django.conf.urls import url
+ from django.urls import path
from myapp.views import MyView
urlpatterns = [
- url(r'^mine/$', MyView.as_view(), name='my-view'),
+ path('mine/', MyView.as_view(), name='my-view'),
]
**Attributes**
@@ -144,12 +144,12 @@ MRO is an acronym for Method Resolution Order.
**Example urls.py**::
- from django.conf.urls import url
+ from django.urls import path
from myapp.views import HomePageView
urlpatterns = [
- url(r'^$', HomePageView.as_view(), name='home'),
+ path('', HomePageView.as_view(), name='home'),
]
**Context**
@@ -208,15 +208,15 @@ MRO is an acronym for Method Resolution Order.
**Example urls.py**::
- from django.conf.urls import url
+ from django.urls import path
from django.views.generic.base import RedirectView
from article.views import ArticleCounterRedirectView, ArticleDetail
urlpatterns = [
- url(r'^counter/(?P<pk>[0-9]+)/$', ArticleCounterRedirectView.as_view(), name='article-counter'),
- url(r'^details/(?P<pk>[0-9]+)/$', ArticleDetail.as_view(), name='article-detail'),
- url(r'^go-to-django/$', RedirectView.as_view(url='https://djangoproject.com'), name='go-to-django'),
+ path('counter/<int:pk>/', ArticleCounterRedirectView.as_view(), name='article-counter'),
+ path('details/<int:pk>/', ArticleDetail.as_view(), name='article-detail'),
+ path('go-to-django/', RedirectView.as_view(url='https://djangoproject.com'), name='go-to-django'),
]
**Attributes**
diff --git a/docs/ref/class-based-views/generic-date-based.txt b/docs/ref/class-based-views/generic-date-based.txt
index 7b50d099ba..a42896c058 100644
--- a/docs/ref/class-based-views/generic-date-based.txt
+++ b/docs/ref/class-based-views/generic-date-based.txt
@@ -63,15 +63,15 @@ views for displaying drilldown pages for date-based data.
**Example myapp/urls.py**::
- from django.conf.urls import url
+ from django.urls import path
from django.views.generic.dates import ArchiveIndexView
from myapp.models import Article
urlpatterns = [
- url(r'^archive/$',
- ArchiveIndexView.as_view(model=Article, date_field="pub_date"),
- name="article_archive"),
+ path('archive/',
+ ArchiveIndexView.as_view(model=Article, date_field="pub_date"),
+ name="article_archive"),
]
**Example myapp/article_archive.html**:
@@ -162,14 +162,14 @@ views for displaying drilldown pages for date-based data.
**Example myapp/urls.py**::
- from django.conf.urls import url
+ from django.urls import path
from myapp.views import ArticleYearArchiveView
urlpatterns = [
- url(r'^(?P<year>[0-9]{4})/$',
- ArticleYearArchiveView.as_view(),
- name="article_year_archive"),
+ path('<int:year>/',
+ ArticleYearArchiveView.as_view(),
+ name="article_year_archive"),
]
**Example myapp/article_archive_year.html**:
@@ -254,19 +254,19 @@ views for displaying drilldown pages for date-based data.
**Example myapp/urls.py**::
- from django.conf.urls import url
+ from django.urls import path
from myapp.views import ArticleMonthArchiveView
urlpatterns = [
- # Example: /2012/aug/
- url(r'^(?P<year>[0-9]{4})/(?P<month>[-\w]+)/$',
- ArticleMonthArchiveView.as_view(),
- name="archive_month"),
# Example: /2012/08/
- url(r'^(?P<year>[0-9]{4})/(?P<month>[0-9]+)/$',
- ArticleMonthArchiveView.as_view(month_format='%m'),
- name="archive_month_numeric"),
+ path('<int:year>/<int:month>/',
+ ArticleMonthArchiveView.as_view(month_format='%m'),
+ name="archive_month_numeric"),
+ # Example: /2012/aug/
+ path('<int:year>/<str:month>/',
+ ArticleMonthArchiveView.as_view(),
+ name="archive_month"),
]
**Example myapp/article_archive_month.html**:
@@ -356,15 +356,15 @@ views for displaying drilldown pages for date-based data.
**Example myapp/urls.py**::
- from django.conf.urls import url
+ from django.urls import path
from myapp.views import ArticleWeekArchiveView
urlpatterns = [
# Example: /2012/week/23/
- url(r'^(?P<year>[0-9]{4})/week/(?P<week>[0-9]+)/$',
- ArticleWeekArchiveView.as_view(),
- name="archive_week"),
+ path('<int:year>/week/<int:week>/',
+ ArticleWeekArchiveView.as_view(),
+ name="archive_week"),
]
**Example myapp/article_archive_week.html**:
@@ -468,15 +468,15 @@ views for displaying drilldown pages for date-based data.
**Example myapp/urls.py**::
- from django.conf.urls import url
+ from django.urls import path
from myapp.views import ArticleDayArchiveView
urlpatterns = [
# Example: /2012/nov/10/
- url(r'^(?P<year>[0-9]{4})/(?P<month>[-\w]+)/(?P<day>[0-9]+)/$',
- ArticleDayArchiveView.as_view(),
- name="archive_day"),
+ path('<int:year>/<str:month>/<int:day>/',
+ ArticleDayArchiveView.as_view(),
+ name="archive_day"),
]
**Example myapp/article_archive_day.html**:
@@ -541,14 +541,14 @@ views for displaying drilldown pages for date-based data.
**Example myapp/urls.py**::
- from django.conf.urls import url
+ from django.urls import path
from myapp.views import ArticleTodayArchiveView
urlpatterns = [
- url(r'^today/$',
- ArticleTodayArchiveView.as_view(),
- name="archive_today"),
+ path('today/',
+ ArticleTodayArchiveView.as_view(),
+ name="archive_today"),
]
.. admonition:: Where is the example template for ``TodayArchiveView``?
@@ -591,13 +591,13 @@ views for displaying drilldown pages for date-based data.
**Example myapp/urls.py**::
- from django.conf.urls import url
+ from django.urls import path
from django.views.generic.dates import DateDetailView
urlpatterns = [
- url(r'^(?P<year>[0-9]{4})/(?P<month>[-\w]+)/(?P<day>[0-9]+)/(?P<pk>[0-9]+)/$',
- DateDetailView.as_view(model=Article, date_field="pub_date"),
- name="archive_date_detail"),
+ path('<int:year>/<str:month>/<int:day>/<int:pk>/',
+ DateDetailView.as_view(model=Article, date_field="pub_date"),
+ name="archive_date_detail"),
]
**Example myapp/article_detail.html**:
diff --git a/docs/ref/class-based-views/generic-display.txt b/docs/ref/class-based-views/generic-display.txt
index 70da1803d6..16975bdbea 100644
--- a/docs/ref/class-based-views/generic-display.txt
+++ b/docs/ref/class-based-views/generic-display.txt
@@ -54,12 +54,12 @@ many projects they are typically the most commonly used views.
**Example myapp/urls.py**::
- from django.conf.urls import url
+ from django.urls import path
from article.views import ArticleDetailView
urlpatterns = [
- url(r'^(?P<slug>[-\w]+)/$', ArticleDetailView.as_view(), name='article-detail'),
+ path('<slug>/', ArticleDetailView.as_view(), name='article-detail'),
]
**Example myapp/article_detail.html**:
@@ -123,12 +123,12 @@ many projects they are typically the most commonly used views.
**Example myapp/urls.py**::
- from django.conf.urls import url
+ from django.urls import path
from article.views import ArticleListView
urlpatterns = [
- url(r'^$', ArticleListView.as_view(), name='article-list'),
+ path('', ArticleListView.as_view(), name='article-list'),
]
**Example myapp/article_list.html**:
diff --git a/docs/ref/class-based-views/index.txt b/docs/ref/class-based-views/index.txt
index 17bd5315ff..5187000385 100644
--- a/docs/ref/class-based-views/index.txt
+++ b/docs/ref/class-based-views/index.txt
@@ -26,7 +26,7 @@ A class-based view is deployed into a URL pattern using the
:meth:`~django.views.generic.base.View.as_view()` classmethod::
urlpatterns = [
- url(r'^view/$', MyView.as_view(size=42)),
+ path('view/', MyView.as_view(size=42)),
]
.. admonition:: Thread safety with view arguments
diff --git a/docs/ref/class-based-views/mixins-multiple-object.txt b/docs/ref/class-based-views/mixins-multiple-object.txt
index 58260391a8..8f6fcb8d48 100644
--- a/docs/ref/class-based-views/mixins-multiple-object.txt
+++ b/docs/ref/class-based-views/mixins-multiple-object.txt
@@ -15,7 +15,7 @@ Multiple object mixins
* Use the ``page`` parameter in the URLconf. For example, this is what
your URLconf might look like::
- url(r'^objects/page(?P<page>[0-9]+)/$', PaginatedView.as_view()),
+ path('objects/page<int:page>/', PaginatedView.as_view()),
* Pass the page number via the ``page`` query-string parameter. For
example, a URL would look like this::
diff --git a/docs/ref/contrib/admin/admindocs.txt b/docs/ref/contrib/admin/admindocs.txt
index 461813f985..e519bd8ed1 100644
--- a/docs/ref/contrib/admin/admindocs.txt
+++ b/docs/ref/contrib/admin/admindocs.txt
@@ -19,9 +19,9 @@ To activate the :mod:`~django.contrib.admindocs`, you will need to do
the following:
* Add :mod:`django.contrib.admindocs` to your :setting:`INSTALLED_APPS`.
-* Add ``url(r'^admin/doc/', include('django.contrib.admindocs.urls'))`` to
+* Add ``path('admin/doc/', include('django.contrib.admindocs.urls'))`` to
your ``urlpatterns``. Make sure it's included *before* the
- ``r'^admin/'`` entry, so that requests to ``/admin/doc/`` don't get
+ ``'admin/'`` entry, so that requests to ``/admin/doc/`` don't get
handled by the latter entry.
* Install the docutils Python module (http://docutils.sf.net/).
* **Optional:** Using the admindocs bookmarklets requires
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
index 2541bc9aa1..adbd18ef74 100644
--- a/docs/ref/contrib/admin/index.txt
+++ b/docs/ref/contrib/admin/index.txt
@@ -1587,11 +1587,15 @@ templates used by the :class:`ModelAdmin` views:
that ModelAdmin in the same way as a URLconf. Therefore you can extend
them as documented in :doc:`/topics/http/urls`::
+ from django.contrib import admin
+ from django.template.response import TemplateResponse
+ from django.urls import path
+
class MyModelAdmin(admin.ModelAdmin):
def get_urls(self):
urls = super().get_urls()
my_urls = [
- url(r'^my_view/$', self.my_view),
+ path('my_view/', self.my_view),
]
return my_urls + urls
@@ -1643,13 +1647,13 @@ templates used by the :class:`ModelAdmin` views:
def get_urls(self):
urls = super().get_urls()
my_urls = [
- url(r'^my_view/$', self.admin_site.admin_view(self.my_view))
+ path('my_view/', self.admin_site.admin_view(self.my_view))
]
return my_urls + urls
Notice the wrapped view in the fifth line above::
- url(r'^my_view/$', self.admin_site.admin_view(self.my_view))
+ path('my_view/', self.admin_site.admin_view(self.my_view))
This wrapping will protect ``self.my_view`` from unauthorized access and
will apply the :func:`django.views.decorators.cache.never_cache` decorator to
@@ -1659,7 +1663,7 @@ templates used by the :class:`ModelAdmin` views:
performed, you can pass a ``cacheable=True`` argument to
``AdminSite.admin_view()``::
- url(r'^my_view/$', self.admin_site.admin_view(self.my_view, cacheable=True))
+ path('my_view/', self.admin_site.admin_view(self.my_view, cacheable=True))
``ModelAdmin`` views have ``model_admin`` attributes. Other
``AdminSite`` views have ``admin_site`` attributes.
@@ -2767,17 +2771,17 @@ Hooking ``AdminSite`` instances into your URLconf
The last step in setting up the Django admin is to hook your ``AdminSite``
instance into your URLconf. Do this by pointing a given URL at the
``AdminSite.urls`` method. It is not necessary to use
-:func:`~django.conf.urls.include()`.
+:func:`~django.urls.include()`.
In this example, we register the default ``AdminSite`` instance
``django.contrib.admin.site`` at the URL ``/admin/`` ::
# urls.py
- from django.conf.urls import url
from django.contrib import admin
+ from django.urls import path
urlpatterns = [
- url(r'^admin/', admin.site.urls),
+ path('admin/', admin.site.urls),
]
.. _customizing-adminsite:
@@ -2809,12 +2813,12 @@ update :file:`myproject/urls.py` to reference your :class:`AdminSite` subclass.
.. snippet::
:filename: myproject/urls.py
- from django.conf.urls import url
+ from django.urls import path
from myapp.admin import admin_site
urlpatterns = [
- url(r'^myadmin/', admin_site.urls),
+ path('myadmin/', admin_site.urls),
]
Note that you may not want autodiscovery of ``admin`` modules when using your
@@ -2838,12 +2842,12 @@ separate versions of the admin site -- using the ``AdminSite`` instances
respectively::
# urls.py
- from django.conf.urls import url
+ from django.urls import path
from myproject.admin import basic_site, advanced_site
urlpatterns = [
- url(r'^basic-admin/', basic_site.urls),
- url(r'^advanced-admin/', advanced_site.urls),
+ path('basic-admin/', basic_site.urls),
+ path('advanced-admin/', advanced_site.urls),
]
``AdminSite`` instances take a single argument to their constructor, their
@@ -2879,23 +2883,23 @@ your URLconf. Specifically, add these four patterns::
from django.contrib.auth import views as auth_views
- url(
- r'^admin/password_reset/$',
+ path(
+ 'admin/password_reset/',
auth_views.PasswordResetView.as_view(),
name='admin_password_reset',
),
- url(
- r'^admin/password_reset/done/$',
+ path(
+ 'admin/password_reset/done/',
auth_views.PasswordResetDoneView.as_view(),
name='password_reset_done',
),
- url(
- r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$',
+ path(
+ 'reset/<uidb64>/<token>/',
auth_views.PasswordResetConfirmView.as_view(),
name='password_reset_confirm',
),
- url(
- r'^reset/done/$',
+ path(
+ 'reset/done/',
auth_views.PasswordResetCompleteView.as_view(),
name='password_reset_complete',
),
diff --git a/docs/ref/contrib/flatpages.txt b/docs/ref/contrib/flatpages.txt
index 4dcd4b9a5a..5d34ad6bea 100644
--- a/docs/ref/contrib/flatpages.txt
+++ b/docs/ref/contrib/flatpages.txt
@@ -47,7 +47,7 @@ Then either:
3. Add an entry in your URLconf. For example::
urlpatterns = [
- url(r'^pages/', include('django.contrib.flatpages.urls')),
+ path('pages/', include('django.contrib.flatpages.urls')),
]
or:
@@ -74,7 +74,7 @@ There are several ways to include the flat pages in your URLconf. You can
dedicate a particular path to flat pages::
urlpatterns = [
- url(r'^pages/', include('django.contrib.flatpages.urls')),
+ path('pages/', include('django.contrib.flatpages.urls')),
]
You can also set it up as a "catchall" pattern. In this case, it is important
@@ -84,7 +84,7 @@ to place the pattern at the end of the other urlpatterns::
# Your other patterns here
urlpatterns += [
- url(r'^(?P<url>.*/)$', views.flatpage),
+ path('<path:url>', views.flatpage),
]
.. warning::
@@ -100,8 +100,8 @@ tag::
from django.contrib.flatpages import views
urlpatterns += [
- url(r'^about-us/$', views.flatpage, {'url': '/about-us/'}, name='about'),
- url(r'^license/$', views.flatpage, {'url': '/license/'}, name='license'),
+ path('about-us/', views.flatpage, {'url': '/about-us/'}, name='about'),
+ path('license/', views.flatpage, {'url': '/license/'}, name='license'),
]
Using the middleware
@@ -345,15 +345,15 @@ Example
Here's an example of a URLconf using :class:`FlatPageSitemap`::
- from django.conf.urls import url
from django.contrib.flatpages.sitemaps import FlatPageSitemap
from django.contrib.sitemaps.views import sitemap
+ from django.urls import path
urlpatterns = [
# ...
# the sitemap
- url(r'^sitemap\.xml$', sitemap,
+ path('sitemap.xml', sitemap,
{'sitemaps': {'flatpages': FlatPageSitemap}},
name='django.contrib.sitemaps.views.sitemap'),
]
diff --git a/docs/ref/contrib/gis/tutorial.txt b/docs/ref/contrib/gis/tutorial.txt
index 7ab3c81415..10f97333cc 100644
--- a/docs/ref/contrib/gis/tutorial.txt
+++ b/docs/ref/contrib/gis/tutorial.txt
@@ -716,11 +716,11 @@ Let's dive right in. Create a file called ``admin.py`` inside the
Next, edit your ``urls.py`` in the ``geodjango`` application folder as follows::
- from django.conf.urls import url, include
from django.contrib.gis import admin
+ from django.urls import path, include
urlpatterns = [
- url(r'^admin/', admin.site.urls),
+ path('admin/', admin.site.urls),
]
Create an admin user:
diff --git a/docs/ref/contrib/sitemaps.txt b/docs/ref/contrib/sitemaps.txt
index 9196bc2a5f..dd720a8bb0 100644
--- a/docs/ref/contrib/sitemaps.txt
+++ b/docs/ref/contrib/sitemaps.txt
@@ -56,8 +56,8 @@ To activate sitemap generation on your Django site, add this line to your
from django.contrib.sitemaps.views import sitemap
- url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps},
- name='django.contrib.sitemaps.views.sitemap')
+ path('sitemap.xml', sitemap, {'sitemaps': sitemaps},
+ name='django.contrib.sitemaps.views.sitemap')
This tells Django to build a sitemap when a client accesses :file:`/sitemap.xml`.
@@ -283,9 +283,9 @@ Example
Here's an example of a :doc:`URLconf </topics/http/urls>` using
:class:`GenericSitemap`::
- from django.conf.urls import url
from django.contrib.sitemaps import GenericSitemap
from django.contrib.sitemaps.views import sitemap
+ from django.urls import path
from blog.models import Entry
info_dict = {
@@ -298,9 +298,9 @@ Here's an example of a :doc:`URLconf </topics/http/urls>` using
# ...
# the sitemap
- url(r'^sitemap\.xml$', sitemap,
- {'sitemaps': {'blog': GenericSitemap(info_dict, priority=0.6)}},
- name='django.contrib.sitemaps.views.sitemap'),
+ path('sitemap.xml', sitemap,
+ {'sitemaps': {'blog': GenericSitemap(info_dict, priority=0.6)}},
+ name='django.contrib.sitemaps.views.sitemap'),
]
.. _URLconf: ../url_dispatch/
@@ -328,8 +328,8 @@ the ``location`` method of the sitemap. For example::
return reverse(item)
# urls.py
- from django.conf.urls import url
from django.contrib.sitemaps.views import sitemap
+ from django.urls import path
from .sitemaps import StaticViewSitemap
from . import views
@@ -339,12 +339,12 @@ the ``location`` method of the sitemap. For example::
}
urlpatterns = [
- url(r'^$', views.main, name='main'),
- url(r'^about/$', views.about, name='about'),
- url(r'^license/$', views.license, name='license'),
+ path('', views.main, name='main'),
+ path('about/', views.about, name='about'),
+ path('license/', views.license, name='license'),
# ...
- url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps},
- name='django.contrib.sitemaps.views.sitemap')
+ path('sitemap.xml', sitemap, {'sitemaps': sitemaps},
+ name='django.contrib.sitemaps.views.sitemap')
]
@@ -367,9 +367,9 @@ Here's what the relevant URLconf lines would look like for the example above::
from django.contrib.sitemaps import views
urlpatterns = [
- url(r'^sitemap\.xml$', views.index, {'sitemaps': sitemaps}),
- url(r'^sitemap-(?P<section>.+)\.xml$', views.sitemap, {'sitemaps': sitemaps},
- name='django.contrib.sitemaps.views.sitemap'),
+ path('sitemap.xml', views.index, {'sitemaps': sitemaps}),
+ path('sitemap-<section>.xml', views.sitemap, {'sitemaps': sitemaps},
+ name='django.contrib.sitemaps.views.sitemap'),
]
This will automatically generate a :file:`sitemap.xml` file that references
@@ -389,12 +389,12 @@ with a caching decorator -- you must name your sitemap view and pass
from django.views.decorators.cache import cache_page
urlpatterns = [
- url(r'^sitemap\.xml$',
- cache_page(86400)(sitemaps_views.index),
- {'sitemaps': sitemaps, 'sitemap_url_name': 'sitemaps'}),
- url(r'^sitemap-(?P<section>.+)\.xml$',
- cache_page(86400)(sitemaps_views.sitemap),
- {'sitemaps': sitemaps}, name='sitemaps'),
+ path('sitemap.xml',
+ cache_page(86400)(sitemaps_views.index),
+ {'sitemaps': sitemaps, 'sitemap_url_name': 'sitemaps'}),
+ path('sitemap-<section>.xml',
+ cache_page(86400)(sitemaps_views.sitemap),
+ {'sitemaps': sitemaps}, name='sitemaps'),
]
@@ -408,11 +408,11 @@ parameter to the ``sitemap`` and ``index`` views via the URLconf::
from django.contrib.sitemaps import views
urlpatterns = [
- url(r'^custom-sitemap\.xml$', views.index, {
+ path('custom-sitemap.xml', views.index, {
'sitemaps': sitemaps,
'template_name': 'custom_sitemap.html'
}),
- url(r'^custom-sitemap-(?P<section>.+)\.xml$', views.sitemap, {
+ path('custom-sitemap-<section>.xml', views.sitemap, {
'sitemaps': sitemaps,
'template_name': 'custom_sitemap.html'
}, name='django.contrib.sitemaps.views.sitemap'),
diff --git a/docs/ref/contrib/staticfiles.txt b/docs/ref/contrib/staticfiles.txt
index b8cadb5ec8..389f2edbc8 100644
--- a/docs/ref/contrib/staticfiles.txt
+++ b/docs/ref/contrib/staticfiles.txt
@@ -462,10 +462,11 @@ primary URL configuration::
from django.conf import settings
from django.contrib.staticfiles import views
+ from django.urls import re_path
if settings.DEBUG:
urlpatterns += [
- url(r'^static/(?P<path>.*)$', views.serve),
+ re_path(r'^static/(?P<path>.*)$', views.serve),
]
Note, the beginning of the pattern (``r'^static/'``) should be your
diff --git a/docs/ref/contrib/syndication.txt b/docs/ref/contrib/syndication.txt
index d8e59edc85..8fa5965a72 100644
--- a/docs/ref/contrib/syndication.txt
+++ b/docs/ref/contrib/syndication.txt
@@ -77,12 +77,12 @@ a feed of the latest five news items::
To connect a URL to this feed, put an instance of the Feed object in
your :doc:`URLconf </topics/http/urls>`. For example::
- from django.conf.urls import url
+ from django.urls import path
from myproject.feeds import LatestEntriesFeed
urlpatterns = [
# ...
- url(r'^latest/feed/$', LatestEntriesFeed()),
+ path('latest/feed/', LatestEntriesFeed()),
# ...
]
@@ -217,7 +217,7 @@ The police beat feeds could be accessible via URLs like this:
These can be matched with a :doc:`URLconf </topics/http/urls>` line such as::
- url(r'^beats/(?P<beat_id>[0-9]+)/rss/$', BeatFeed()),
+ path('beats/<int:beat_id>/rss/', BeatFeed()),
Like a view, the arguments in the URL are passed to the ``get_object()``
method along with the request object.
@@ -366,13 +366,13 @@ Here's a full example::
And the accompanying URLconf::
- from django.conf.urls import url
+ from django.urls import path
from myproject.feeds import RssSiteNewsFeed, AtomSiteNewsFeed
urlpatterns = [
# ...
- url(r'^sitenews/rss/$', RssSiteNewsFeed()),
- url(r'^sitenews/atom/$', AtomSiteNewsFeed()),
+ path('sitenews/rss/', RssSiteNewsFeed()),
+ path('sitenews/atom/', AtomSiteNewsFeed()),
# ...
]
diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt
index c4ad02f529..49e07aeec2 100644
--- a/docs/ref/templates/builtins.txt
+++ b/docs/ref/templates/builtins.txt
@@ -1115,11 +1115,11 @@ hard-code URLs in your templates::
{% url 'some-url-name' v1 v2 %}
-The first argument is a :func:`~django.conf.urls.url` ``name``. It can be a
-quoted literal or any other context variable. Additional arguments are optional
-and should be space-separated values that will be used as arguments in the URL.
-The example above shows passing positional arguments. Alternatively you may
-use keyword syntax::
+The first argument is a :ref:`URL pattern name <naming-url-patterns>`. It can
+be a quoted literal or any other context variable. Additional arguments are
+optional and should be space-separated values that will be used as arguments in
+the URL. The example above shows passing positional arguments. Alternatively
+you may use keyword syntax::
{% url 'some-url-name' arg1=v1 arg2=v2 %}
@@ -1132,14 +1132,14 @@ takes a client ID (here, ``client()`` is a method inside the views file
.. code-block:: python
- ('^client/([0-9]+)/$', app_views.client, name='app-views-client')
+ path('client/<int:id>/', app_views.client, name='app-views-client')
If this app's URLconf is included into the project's URLconf under a path
such as this:
.. code-block:: python
- ('^clients/', include('project_name.app_name.urls'))
+ path('clients/', include('project_name.app_name.urls'))
...then, in a template, you can create a link to this view like this::
@@ -1179,8 +1179,8 @@ by the context as to the current application.
.. warning::
- Don't forget to put quotes around the :func:`~django.conf.urls.url`
- ``name``, otherwise the value will be interpreted as a context variable!
+ Don't forget to put quotes around the URL pattern ``name``, otherwise the
+ value will be interpreted as a context variable!
.. templatetag:: verbatim
diff --git a/docs/ref/urlresolvers.txt b/docs/ref/urlresolvers.txt
index 2e6bc463dd..aa814a9e40 100644
--- a/docs/ref/urlresolvers.txt
+++ b/docs/ref/urlresolvers.txt
@@ -17,7 +17,7 @@ callable view object. For example, given the following ``url``::
from news import views
- url(r'^archive/$', views.archive, name='news-archive')
+ path('archive/', views.archive, name='news-archive')
you can use any of the following to reverse the URL::
diff --git a/docs/ref/urls.txt b/docs/ref/urls.txt
index 3b6a66032d..f290276dec 100644
--- a/docs/ref/urls.txt
+++ b/docs/ref/urls.txt
@@ -5,7 +5,79 @@
.. module:: django.urls.conf
:synopsis: Functions for use in URLconfs.
-.. currentmodule:: django.conf.urls
+.. currentmodule:: django.urls
+
+``path()``
+==========
+
+.. function:: path(route, view, kwargs=None, name=None)
+
+.. versionadded:: 2.0
+
+Returns an element for inclusion in ``urlpatterns``. For example::
+
+ from django.urls import include, path
+
+ urlpatterns = [
+ path('index/', views.index, name='main-view'),
+ path('bio/<username>/', views.bio, name='bio'),
+ path('articles/<slug:title>/', views.article, name='article-detail'),
+ path('articles/<slug:title>/<int:section>/', views.section, name='article-section'),
+ path('weblog/', include('blog.urls')),
+ ...
+ ]
+
+The ``route`` argument should be a string or
+:func:`~django.utils.translation.gettext_lazy()` (see
+:ref:`translating-urlpatterns`) that contains a URL pattern. The string
+may contain angle brackets (like ``<username>`` above) to capture part of the
+URL and send it as a keyword argument to the view. The angle brackets may
+include a converter specification (like the ``int`` part of ``<int:section>``)
+which limits the characters matched and may also change the type of the
+variable passed to the view. For example, ``<int:section>`` matches a string
+of decimal digits and converts the value to an ``int``. See
+:ref:`how-django-processes-a-request` for more details.
+
+The ``view`` argument is a view function or the result of
+:meth:`~django.views.generic.base.View.as_view` for class-based views. It can
+also be an :func:`django.urls.include`.
+
+The ``kwargs`` argument allows you to pass additional arguments to the view
+function or method. See :ref:`views-extra-options` for an example.
+
+See :ref:`Naming URL patterns <naming-url-patterns>` for why the ``name``
+argument is useful.
+
+``re_path()``
+=============
+
+.. function:: re_path(route, view, kwargs=None, name=None)
+
+.. versionadded:: 2.0
+
+Returns an element for inclusion in ``urlpatterns``. For example::
+
+ from django.urls import include, re_path
+
+ urlpatterns = [
+ re_path(r'^index/$', views.index, name='index'),
+ re_path(r'^bio/(?P<username>\w+)/$', views.bio, name='bio'),
+ re_path(r'^weblog/', include('blog.urls')),
+ ...
+ ]
+
+The ``route`` argument should be a string or
+:func:`~django.utils.translation.gettext_lazy()` (see
+:ref:`translating-urlpatterns`) that contains a regular expression compatible
+with Python's :py:mod:`re` module. Strings typically use raw string syntax
+(``r''``) so that they can contain sequences like ``\d`` without the need to
+escape the backslash with another backslash. When a match is made, captured
+groups from the regular expression are passed to the view -- as named arguments
+if the groups are named, and as positional arguments otherwise. The values are
+passed as strings, without any type conversion.
+
+The ``view``, ``kwargs`` and ``name`` arguments are the same as for
+:func:`~django.urls.path()`.
``include()``
=============
@@ -30,7 +102,7 @@
:arg module: URLconf module (or module name)
:arg namespace: Instance namespace for the URL entries being included
:type namespace: string
- :arg pattern_list: Iterable of :func:`django.conf.urls.url` instances
+ :arg pattern_list: Iterable of :func:`~django.urls.path` and/or :func:`~django.urls.re_path` instances.
:arg app_namespace: Application namespace for the URL entries being included
:type app_namespace: string
:arg instance_namespace: Instance namespace for the URL entries being included
@@ -43,6 +115,20 @@ See :ref:`including-other-urlconfs` and :ref:`namespaces-and-include`.
In older versions, this function is located in ``django.conf.urls``. The
old location still works for backwards compatibility.
+``register_converter()``
+========================
+
+.. function:: register_converter(converter, type_name)
+
+.. versionadded:: 2.0
+
+The function for registering a converter for use in :func:`~django.urls.path()`
+``route``\s.
+
+The ``converter`` argument is a converter class, and ``type_name`` is the
+converter name to use in path patterns. See
+:ref:`registering-custom-path-converters` for an example.
+
==================================================
``django.conf.urls`` functions for use in URLconfs
==================================================
@@ -68,32 +154,8 @@ Helper function to return a URL pattern for serving files in debug mode::
.. function:: url(regex, view, kwargs=None, name=None)
-``urlpatterns`` should be a list of ``url()`` instances. For example::
-
- from django.conf.urls import include, url
-
- urlpatterns = [
- url(r'^index/$', index_view, name='main-view'),
- url(r'^weblog/', include('blog.urls')),
- ...
- ]
-
-The ``regex`` parameter should be a string or
-:func:`~django.utils.translation.gettext_lazy()` (see
-:ref:`translating-urlpatterns`) that contains a regular expression compatible
-with Python's :py:mod:`re` module. Strings typically use raw string syntax
-(``r''``) so that they can contain sequences like ``\d`` without the need to
-escape the backslash with another backslash.
-
-The ``view`` parameter is a view function or the result of
-:meth:`~django.views.generic.base.View.as_view` for class-based views. It can
-also be an :func:`include`.
-
-The ``kwargs`` parameter allows you to pass additional arguments to the view
-function or method. See :ref:`views-extra-options` for an example.
-
-See :ref:`Naming URL patterns <naming-url-patterns>` for why the ``name``
-parameter is useful.
+This function is an alias to :func:`django.urls.re_path()`. It's likely to be
+deprecated in a future release.
``handler400``
==============
diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt
index 240cb80485..55a733f376 100644
--- a/docs/ref/utils.txt
+++ b/docs/ref/utils.txt
@@ -823,8 +823,8 @@ appropriate entities.
from django.utils.translation import pgettext_lazy
urlpatterns = [
- url(format_lazy(r'{person}/(?P<pk>\d+)/$', person=pgettext_lazy('URL', 'person')),
- PersonDetailView.as_view()),
+ path(format_lazy('{person}/<int:pk>/', person=pgettext_lazy('URL', 'person')),
+ PersonDetailView.as_view()),
]
This example allows translators to translate part of the URL. If "person"
diff --git a/docs/ref/views.txt b/docs/ref/views.txt
index dd1897c915..37204e2fda 100644
--- a/docs/ref/views.txt
+++ b/docs/ref/views.txt
@@ -26,13 +26,14 @@ built-in handling for user-uploaded files, but you can have Django serve your
:setting:`MEDIA_ROOT` by appending something like this to your URLconf::
from django.conf import settings
+ from django.urls import re_path
from django.views.static import serve
# ... the rest of your URLconf goes here ...
if settings.DEBUG:
urlpatterns += [
- url(r'^media/(?P<path>.*)$', serve, {
+ re_path(r'^media/(?P<path>.*)$', serve, {
'document_root': settings.MEDIA_ROOT,
}),
]
diff --git a/docs/releases/1.4.txt b/docs/releases/1.4.txt
index 3a8b52db57..13cff1f0b3 100644
--- a/docs/releases/1.4.txt
+++ b/docs/releases/1.4.txt
@@ -1229,9 +1229,8 @@ disable this backward-compatibility shim and deprecation warning.
``django.conf.urls.defaults``
-----------------------------
-Until Django 1.3, the functions :func:`~django.conf.urls.include`,
-``patterns()`` and :func:`~django.conf.urls.url` plus
-:data:`~django.conf.urls.handler404`, :data:`~django.conf.urls.handler500`
+Until Django 1.3, the ``include()``, ``patterns()``, and ``url()`` functions,
+plus :data:`~django.conf.urls.handler404` and :data:`~django.conf.urls.handler500`
were located in a ``django.conf.urls.defaults`` module.
In Django 1.4, they live in :mod:`django.conf.urls`.
diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt
index 9d0d9efd93..2b012191cd 100644
--- a/docs/releases/1.9.txt
+++ b/docs/releases/1.9.txt
@@ -657,7 +657,7 @@ URLs
* The application namespace can now be set using an ``app_name`` attribute
on the included module or object. It can also be set by passing a 2-tuple
of (<list of patterns>, <application namespace>) as the first argument to
- :func:`~django.conf.urls.include`.
+ ``include()``.
* System checks have been added for common URL pattern mistakes.
@@ -1233,8 +1233,8 @@ extending. This change necessitated a new template loader API. The old
Details about the new API can be found :ref:`in the template loader
documentation <custom-template-loaders>`.
-Passing a 3-tuple or an ``app_name`` to :func:`~django.conf.urls.include()`
----------------------------------------------------------------------------
+Passing a 3-tuple or an ``app_name`` to ``include()``
+-----------------------------------------------------
The instance namespace part of passing a tuple as an argument to ``include()``
has been replaced by passing the ``namespace`` argument to ``include()``. For
diff --git a/docs/releases/2.0.txt b/docs/releases/2.0.txt
index b45e494800..457e69ea9e 100644
--- a/docs/releases/2.0.txt
+++ b/docs/releases/2.0.txt
@@ -46,6 +46,32 @@ be compatible with Django 2.0.
What's new in Django 2.0
========================
+Simplified URL routing syntax
+-----------------------------
+
+The new :func:`django.urls.path()` function allows a simpler, more readable URL
+routing syntax. For example, this example from previous Django releases::
+
+ url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
+
+could be written as::
+
+ path('articles/<int:year>/', views.year_archive),
+
+The new syntax supports type coercion of URL parameters. In the example, the
+view will receive the ``year`` keyword argument as an integer rather than as
+a string.
+
+The ``django.conf.urls.url()`` function from previous versions is now available
+as :func:`django.urls.re_path`, however, the old location remains for backwards
+compatibility, without an imminent deprecation. The old
+``django.conf.urls.include()`` function is now importable from ``django.urls``
+so you can use ``from django.urls import include, path, re_path`` in your
+URLconfs.
+
+The :doc:`/topics/http/urls` document is rewritten to feature the new syntax
+and provide more details.
+
Mobile-friendly ``contrib.admin``
---------------------------------
diff --git a/docs/topics/auth/default.txt b/docs/topics/auth/default.txt
index 4d8fbc37c9..85398f428f 100644
--- a/docs/topics/auth/default.txt
+++ b/docs/topics/auth/default.txt
@@ -502,7 +502,7 @@ The ``login_required`` decorator
from django.contrib.auth import views as auth_views
- url(r'^accounts/login/$', auth_views.LoginView.as_view()),
+ path('accounts/login/', auth_views.LoginView.as_view()),
The :setting:`settings.LOGIN_URL <LOGIN_URL>` also accepts view function
names and :ref:`named URL patterns <naming-url-patterns>`. This allows you
@@ -896,7 +896,7 @@ easiest way is to include the provided URLconf in ``django.contrib.auth.urls``
in your own URLconf, for example::
urlpatterns = [
- url('^', include('django.contrib.auth.urls')),
+ path('', include('django.contrib.auth.urls')),
]
This will include the following URL patterns::
@@ -919,7 +919,7 @@ your URLconf::
from django.contrib.auth import views as auth_views
urlpatterns = [
- url('^change-password/$', auth_views.PasswordChangeView.as_view()),
+ path('change-password/', auth_views.PasswordChangeView.as_view()),
]
The views have optional arguments you can use to alter the behavior of the
@@ -928,8 +928,8 @@ provide the ``template_name`` argument. A way to do this is to provide keyword
arguments in the URLconf, these will be passed on to the view. For example::
urlpatterns = [
- url(
- '^change-password/$',
+ path(
+ 'change-password/',
auth_views.PasswordChangeView.as_view(template_name='change-password.html'),
),
]
@@ -1035,7 +1035,7 @@ implementation details see :ref:`using-the-views`.
the ``as_view`` method in your URLconf. For example, this URLconf line would
use :file:`myapp/login.html` instead::
- url(r'^accounts/login/$', auth_views.LoginView.as_view(template_name='myapp/login.html')),
+ path('accounts/login/', auth_views.LoginView.as_view(template_name='myapp/login.html')),
You can also specify the name of the ``GET`` field which contains the URL
to redirect to after login using ``redirect_field_name``. By default, the
diff --git a/docs/topics/cache.txt b/docs/topics/cache.txt
index d2aa8f98ec..6e6564d3e2 100644
--- a/docs/topics/cache.txt
+++ b/docs/topics/cache.txt
@@ -591,7 +591,7 @@ multiple URLs point at the same view, each URL will be cached separately.
Continuing the ``my_view`` example, if your URLconf looks like this::
urlpatterns = [
- url(r'^foo/([0-9]{1,2})/$', my_view),
+ path('foo/<int:code>/', my_view),
]
then requests to ``/foo/1/`` and ``/foo/23/`` will be cached separately, as
@@ -637,7 +637,7 @@ Doing so is easy: simply wrap the view function with ``cache_page`` when you
refer to it in the URLconf. Here's the old URLconf from earlier::
urlpatterns = [
- url(r'^foo/([0-9]{1,2})/$', my_view),
+ path('foo/<int:code>/', my_view),
]
Here's the same thing, with ``my_view`` wrapped in ``cache_page``::
@@ -645,7 +645,7 @@ Here's the same thing, with ``my_view`` wrapped in ``cache_page``::
from django.views.decorators.cache import cache_page
urlpatterns = [
- url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
+ path('foo/<int:code>/', cache_page(60 * 15)(my_view)),
]
.. templatetag:: cache
diff --git a/docs/topics/class-based-views/generic-display.txt b/docs/topics/class-based-views/generic-display.txt
index 456c953cb1..2f41b0b500 100644
--- a/docs/topics/class-based-views/generic-display.txt
+++ b/docs/topics/class-based-views/generic-display.txt
@@ -117,11 +117,11 @@ Now we need to define a view::
Finally hook that view into your urls::
# urls.py
- from django.conf.urls import url
+ from django.urls import path
from books.views import PublisherList
urlpatterns = [
- url(r'^publishers/$', PublisherList.as_view()),
+ path('publishers/', PublisherList.as_view()),
]
That's all the Python code we need to write. We still need to write a template,
@@ -332,11 +332,11 @@ various useful things are stored on ``self``; as well as the request
Here, we have a URLconf with a single captured group::
# urls.py
- from django.conf.urls import url
+ from django.urls import path
from books.views import PublisherBookList
urlpatterns = [
- url(r'^books/([\w-]+)/$', PublisherBookList.as_view()),
+ path('books/<publisher>/', PublisherBookList.as_view()),
]
Next, we'll write the ``PublisherBookList`` view itself::
@@ -351,7 +351,7 @@ Next, we'll write the ``PublisherBookList`` view itself::
template_name = 'books/books_by_publisher.html'
def get_queryset(self):
- self.publisher = get_object_or_404(Publisher, name=self.args[0])
+ self.publisher = get_object_or_404(Publisher, name=self.kwargs['publisher'])
return Book.objects.filter(publisher=self.publisher)
As you can see, it's quite easy to add more logic to the queryset selection;
@@ -398,12 +398,12 @@ updated.
First, we'd need to add an author detail bit in the URLconf to point to a
custom view::
- from django.conf.urls import url
+ from django.urls import path
from books.views import AuthorDetailView
urlpatterns = [
#...
- url(r'^authors/(?P<pk>[0-9]+)/$', AuthorDetailView.as_view(), name='author-detail'),
+ path('authors/<int:pk>/', AuthorDetailView.as_view(), name='author-detail'),
]
Then we'd write our new view -- ``get_object`` is the method that retrieves the
diff --git a/docs/topics/class-based-views/generic-editing.txt b/docs/topics/class-based-views/generic-editing.txt
index 3fde51253a..69f2158021 100644
--- a/docs/topics/class-based-views/generic-editing.txt
+++ b/docs/topics/class-based-views/generic-editing.txt
@@ -149,14 +149,14 @@ Finally, we hook these new views into the URLconf:
.. snippet::
:filename: urls.py
- from django.conf.urls import url
+ from django.urls import path
from myapp.views import AuthorCreate, AuthorUpdate, AuthorDelete
urlpatterns = [
# ...
- url(r'author/add/$', AuthorCreate.as_view(), name='author-add'),
- url(r'author/(?P<pk>[0-9]+)/$', AuthorUpdate.as_view(), name='author-update'),
- url(r'author/(?P<pk>[0-9]+)/delete/$', AuthorDelete.as_view(), name='author-delete'),
+ path('author/add/', AuthorCreate.as_view(), name='author-add'),
+ path('author/<int:pk>/', AuthorUpdate.as_view(), name='author-update'),
+ path('author/<int:pk>/delete/', AuthorDelete.as_view(), name='author-delete'),
]
.. note::
diff --git a/docs/topics/class-based-views/index.txt b/docs/topics/class-based-views/index.txt
index 91dd6ff944..6a629cb887 100644
--- a/docs/topics/class-based-views/index.txt
+++ b/docs/topics/class-based-views/index.txt
@@ -38,11 +38,11 @@ URLconf. If you're only changing a few simple attributes on a class-based view,
you can simply pass them into the
:meth:`~django.views.generic.base.View.as_view` method call itself::
- from django.conf.urls import url
+ from django.urls import path
from django.views.generic import TemplateView
urlpatterns = [
- url(r'^about/$', TemplateView.as_view(template_name="about.html")),
+ path('about/', TemplateView.as_view(template_name="about.html")),
]
Any arguments passed to :meth:`~django.views.generic.base.View.as_view` will
@@ -75,11 +75,11 @@ class method instead, which provides a function-like entry to class-based
views::
# urls.py
- from django.conf.urls import url
+ from django.urls import path
from some_app.views import AboutView
urlpatterns = [
- url(r'^about/$', AboutView.as_view()),
+ path('about/', AboutView.as_view()),
]
@@ -100,11 +100,11 @@ preferable to ask the API when the most recent book was published.
We map the URL to book list view in the URLconf::
- from django.conf.urls import url
+ from django.urls import path
from books.views import BookListView
urlpatterns = [
- url(r'^books/$', BookListView.as_view()),
+ path('books/', BookListView.as_view()),
]
And the view::
diff --git a/docs/topics/class-based-views/intro.txt b/docs/topics/class-based-views/intro.txt
index 32562a8744..f4a5f5ac24 100644
--- a/docs/topics/class-based-views/intro.txt
+++ b/docs/topics/class-based-views/intro.txt
@@ -89,11 +89,11 @@ request to a matching method if one is defined, or raises
:class:`~django.http.HttpResponseNotAllowed` if not::
# urls.py
- from django.conf.urls import url
+ from django.urls import path
from myapp.views import MyView
urlpatterns = [
- url(r'^about/$', MyView.as_view()),
+ path('about/', MyView.as_view()),
]
@@ -130,7 +130,7 @@ Another option is to configure class attributes as keyword arguments to the
:meth:`~django.views.generic.base.View.as_view` call in the URLconf::
urlpatterns = [
- url(r'^about/$', GreetingView.as_view(greeting="G'day")),
+ path('about/', GreetingView.as_view(greeting="G'day")),
]
.. note::
@@ -245,8 +245,8 @@ The easiest place to do this is in the URLconf where you deploy your view::
from .views import VoteView
urlpatterns = [
- url(r'^about/$', login_required(TemplateView.as_view(template_name="secret.html"))),
- url(r'^vote/$', permission_required('polls.can_vote')(VoteView.as_view())),
+ path('about/', login_required(TemplateView.as_view(template_name="secret.html"))),
+ path('vote/', permission_required('polls.can_vote')(VoteView.as_view())),
]
This approach applies the decorator on a per-instance basis. If you
diff --git a/docs/topics/class-based-views/mixins.txt b/docs/topics/class-based-views/mixins.txt
index 8da0834866..4a47af6f11 100644
--- a/docs/topics/class-based-views/mixins.txt
+++ b/docs/topics/class-based-views/mixins.txt
@@ -258,12 +258,12 @@ We can hook this into our URLs easily enough:
.. snippet::
:filename: urls.py
- from django.conf.urls import url
+ from django.urls import path
from books.views import RecordInterest
urlpatterns = [
#...
- url(r'^author/(?P<pk>[0-9]+)/interest/$', RecordInterest.as_view(), name='author-interest'),
+ path('author/<int:pk>/interest/', RecordInterest.as_view(), name='author-interest'),
]
Note the ``pk`` named group, which
diff --git a/docs/topics/http/urls.txt b/docs/topics/http/urls.txt
index d5bae7f072..449f421775 100644
--- a/docs/topics/http/urls.txt
+++ b/docs/topics/http/urls.txt
@@ -19,8 +19,7 @@ Overview
To design URLs for an app, you create a Python module informally called a
**URLconf** (URL configuration). This module is pure Python code and is a
-simple mapping between URL patterns (simple regular expressions) to Python
-functions (your views).
+mapping between URL path expressions to Python functions (your views).
This mapping can be as short or as long as needed. It can reference other
mappings. And, because it's pure Python code, it can be constructed
@@ -45,25 +44,26 @@ algorithm the system follows to determine which Python code to execute:
:setting:`ROOT_URLCONF` setting.
2. Django loads that Python module and looks for the variable
- ``urlpatterns``. This should be a Python list of :func:`django.conf.urls.url`
- instances.
+ ``urlpatterns``. This should be a Python list of :func:`django.urls.path`
+ and/or :func:`django.urls.re_path` instances.
3. Django runs through each URL pattern, in order, and stops at the first
one that matches the requested URL.
-4. Once one of the regexes matches, Django imports and calls the given view,
- which is a simple Python function (or a :doc:`class-based view
+4. Once one of the URL patterns matches, Django imports and calls the given
+ view, which is a simple Python function (or a :doc:`class-based view
</topics/class-based-views/index>`). The view gets passed the following
arguments:
* An instance of :class:`~django.http.HttpRequest`.
- * If the matched regular expression returned no named groups, then the
+ * If the matched URL pattern returned no named groups, then the
matches from the regular expression are provided as positional arguments.
- * The keyword arguments are made up of any named groups matched by the
- regular expression, overridden by any arguments specified in the optional
- ``kwargs`` argument to :func:`django.conf.urls.url`.
+ * The keyword arguments are made up of any named parts matched by the
+ path expression, overridden by any arguments specified in the optional
+ ``kwargs`` argument to :func:`django.urls.path` or
+ :func:`django.urls.re_path`.
-5. If no regex matches, or if an exception is raised during any
+5. If no URL pattern matches, or if an exception is raised during any
point in this process, Django invokes an appropriate
error-handling view. See `Error handling`_ below.
@@ -72,36 +72,33 @@ Example
Here's a sample URLconf::
- from django.conf.urls import url
+ from django.urls import path
from . import views
urlpatterns = [
- url(r'^articles/2003/$', views.special_case_2003),
- url(r'^articles/([0-9]{4})/$', views.year_archive),
- url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
- url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
+ path('articles/2003/', views.special_case_2003),
+ path('articles/<int:year>/', views.year_archive),
+ path('articles/<int:year>/<int:month>/', views.month_archive),
+ path('articles/<int:year>/<int:month>/<slug>/', views.article_detail),
]
Notes:
-* To capture a value from the URL, just put parenthesis around it.
+* To capture a value from the URL, use angle brackets.
-* There's no need to add a leading slash, because every URL has that. For
- example, it's ``^articles``, not ``^/articles``.
+* Captured values can optionally include a converter type. For example, use
+ ``<int:name>`` to capture an integer parameter. If a converter isn't included,
+ any string, excluding a ``/`` character, is matched.
-* The ``'r'`` in front of each regular expression string is optional but
- recommended. It tells Python that a string is "raw" -- that nothing in
- the string should be escaped. See `Dive Into Python's explanation`_.
+* There's no need to add a leading slash, because every URL has that. For
+ example, it's ``articles``, not ``/articles``.
Example requests:
* A request to ``/articles/2005/03/`` would match the third entry in the
list. Django would call the function
- ``views.month_archive(request, '2005', '03')``.
-
-* ``/articles/2005/3/`` would not match any URL patterns, because the
- third entry in the list requires two digits for the month.
+ ``views.month_archive(request, year=2005, month=3)``.
* ``/articles/2003/`` would match the first pattern in the list, not the
second one, because the patterns are tested in order, and the first one
@@ -112,66 +109,163 @@ Example requests:
* ``/articles/2003`` would not match any of these patterns, because each
pattern requires that the URL end with a slash.
-* ``/articles/2003/03/03/`` would match the final pattern. Django would call
- the function ``views.article_detail(request, '2003', '03', '03')``.
+* ``/articles/2003/03/building-a-django-site/`` would match the final
+ pattern. Django would call the function
+ ``views.article_detail(request, year=2003, month=3, slug="building-a-django-site")``.
+
+Path converters
+===============
+
+The following path converters are available by default:
+
+* ``str`` - Matches any non-empty string, excluding the path separator, ``'/'``.
+ This is the default if a converter isn't included in the expression.
+
+* ``int`` - Matches zero or any positive integer. Returns an `int`.
+
+* ``slug`` - Matches any slug string consisting of ASCII letters or numbers,
+ plus the hyphen and underscore characters. For example,
+ ``building-your-1st-django-site``.
+
+* ``uuid`` - Matches a formatted UUID. For example,
+ ``075194d3-6885-417e-a8a8-6c931e272f00``. Returns a :class:`~uuid.UUID`
+ instance.
+
+* ``path`` - Matches any non-empty string, including the path separator,
+ ``'/'``. This allows you to match against a complete URL path rather than
+ just a segment of a URL path as with ``str``.
+
+.. _registering-custom-path-converters:
+
+Registering custom path converters
+==================================
+
+For more complex matching requirements, you can define your own path converters.
+
+A converter is a class that includes the following:
+
+* A ``regex`` class attribute, as a string.
+
+* A ``to_python(self, value)`` method, which handles converting the matched
+ string into the type that should be passed to the view function. It should
+ raise ``ValueError`` if it can't convert the given value.
+
+* A ``to_url(self, value)`` method, which handles converting the Python type
+ into a string to be used in the URL.
+
+For example::
+
+ class FourDigitYearConverter:
+ regex = '[0-9]{4}'
+
+ def to_python(self, value):
+ return int(value)
+
+ def to_url(self, value):
+ return '%04d' % value
+
+Register custom converter classes in your URLconf using
+:func:`~django.urls.register_converter`::
+
+ from django.urls import register_converter, path
-.. _Dive Into Python's explanation: http://www.diveintopython3.net/regular-expressions.html#streetaddresses
+ from . import converters, views
-Named groups
-============
+ register_converter(converters.FourDigitYearConverter, 'yyyy')
-The above example used simple, *non-named* regular-expression groups (via
-parenthesis) to capture bits of the URL and pass them as *positional* arguments
-to a view. In more advanced usage, it's possible to use *named*
-regular-expression groups to capture URL bits and pass them as *keyword*
-arguments to a view.
+ urlpatterns = [
+ path('articles/2003/', views.special_case_2003),
+ path('articles/<yyyy:year>/', views.year_archive),
+ ...
+ ]
-In Python regular expressions, the syntax for named regular-expression groups
+Using regular expressions
+=========================
+
+If the paths and converters syntax isn't sufficient for defining your URL
+patterns, you can also use regular expressions. To do so, use
+:func:`~django.urls.re_path` instead of :func:`~django.urls.path`.
+
+In Python regular expressions, the syntax for named regular expression groups
is ``(?P<name>pattern)``, where ``name`` is the name of the group and
``pattern`` is some pattern to match.
-Here's the above example URLconf, rewritten to use named groups::
+Here's the example URLconf from earlier, rewritten using regular expressions::
- from django.conf.urls import url
+ from django.urls import path, re_path
from . import views
urlpatterns = [
- url(r'^articles/2003/$', views.special_case_2003),
- url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
- url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
- url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
+ path('articles/2003/', views.special_case_2003),
+ re_path('articles/(?P<year>[0-9]{4})/', views.year_archive),
+ re_path('articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/', views.month_archive),
+ re_path('articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[^/]+)/', views.article_detail),
]
-This accomplishes exactly the same thing as the previous example, with one
-subtle difference: The captured values are passed to view functions as keyword
-arguments rather than positional arguments. For example:
+This accomplishes roughly the same thing as the previous example, except:
+
+* The exact URLs that will match are slightly more constrained. For example,
+ the year 10000 will no longer match since the year integers are constrained
+ to be exactly four digits long.
+
+* Each captured argument is sent to the view as a string, regardless of what
+ sort of match the regular expression makes.
+
+When switching from using :func:`~django.urls.path` to
+:func:`~django.urls.re_path` or vice versa, it's particularly important to be
+aware that the type of the view arguments may change, and so you may need to
+adapt your views.
+
+Using unnamed regular expression groups
+---------------------------------------
+
+As well as the named group syntax, e.g. ``(?P<year>[0-9]{4})``, you can
+also use the shorter unnamed group, e.g. ``([0-9]{4})``.
+
+This usage isn't particularly recommended as it makes it easier to accidentally
+introduce errors between the intended meaning of a match and the arguments
+of the view.
+
+In either case, using only one style within an given regex is recommended. When
+both styles are mixed, any unnamed groups are ignored and only named groups are
+passed to the view function.
-* A request to ``/articles/2005/03/`` would call the function
- ``views.month_archive(request, year='2005', month='03')``, instead
- of ``views.month_archive(request, '2005', '03')``.
+Nested arguments
+----------------
-* A request to ``/articles/2003/03/03/`` would call the function
- ``views.article_detail(request, year='2003', month='03', day='03')``.
+Regular expressions allow nested arguments, and Django will resolve them and
+pass them to the view. When reversing, Django will try to fill in all outer
+captured arguments, ignoring any nested captured arguments. Consider the
+following URL patterns which optionally take a page argument::
-In practice, this means your URLconfs are slightly more explicit and less prone
-to argument-order bugs -- and you can reorder the arguments in your views'
-function definitions. Of course, these benefits come at the cost of brevity;
-some developers find the named-group syntax ugly and too verbose.
+ from django.urls import re_path
-The matching/grouping algorithm
--------------------------------
+ urlpatterns = [
+ re_path(r'blog/(page-(\d+)/)?$', blog_articles), # bad
+ re_path(r'comments/(?:page-(?P<page_number>\d+)/)?$', comments), # good
+ ]
-Here's the algorithm the URLconf parser follows, with respect to named groups
-vs. non-named groups in a regular expression:
+Both patterns use nested arguments and will resolve: for example,
+``blog/page-2/`` will result in a match to ``blog_articles`` with two
+positional arguments: ``page-2/`` and ``2``. The second pattern for
+``comments`` will match ``comments/page-2/`` with keyword argument
+``page_number`` set to 2. The outer argument in this case is a non-capturing
+argument ``(?:...)``.
-1. If there are any named arguments, it will use those, ignoring non-named
- arguments.
+The ``blog_articles`` view needs the outermost captured argument to be reversed,
+``page-2/`` or no arguments in this case, while ``comments`` can be reversed
+with either no arguments or a value for ``page_number``.
-2. Otherwise, it will pass all non-named arguments as positional arguments.
+Nested captured arguments create a strong coupling between the view arguments
+and the URL as illustrated by ``blog_articles``: the view receives part of the
+URL (``page-2/``) instead of only the value the view is interested in. This
+coupling is even more pronounced when reversing, since to reverse the view we
+need to pass the piece of URL instead of the page number.
-In both cases, any extra keyword arguments that have been given as per `Passing
-extra options to view functions`_ (below) will also be passed to the view.
+As a rule of thumb, only capture the values the view needs to work with and
+use non-capturing arguments when the regular expression needs an argument but
+the view ignores it.
What the URLconf searches against
=================================
@@ -189,18 +283,6 @@ The URLconf doesn't look at the request method. In other words, all request
methods -- ``POST``, ``GET``, ``HEAD``, etc. -- will be routed to the same
function for the same URL.
-Captured arguments are always strings
-=====================================
-
-Each captured argument is sent to the view as a plain Python string, regardless
-of what sort of match the regular expression makes. For example, in this
-URLconf line::
-
- url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
-
-...the ``year`` argument passed to ``views.year_archive()`` will be a string,
- not an integer, even though the ``[0-9]{4}`` will only match integer strings.
-
Specifying defaults for view arguments
======================================
@@ -208,25 +290,25 @@ A convenient trick is to specify default parameters for your views' arguments.
Here's an example URLconf and view::
# URLconf
- from django.conf.urls import url
+ from django.urls import path
from . import views
urlpatterns = [
- url(r'^blog/$', views.page),
- url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
+ path('blog/', views.page),
+ path('blog/page<int:num>/', views.page),
]
# View (in blog/views.py)
- def page(request, num="1"):
+ def page(request, num=1):
# Output the appropriate page of blog entries, according to num.
...
In the above example, both URL patterns point to the same view --
``views.page`` -- but the first pattern doesn't capture anything from the
URL. If the first pattern matches, the ``page()`` function will use its
-default argument for ``num``, ``"1"``. If the second pattern matches,
-``page()`` will use whatever ``num`` value was captured by the regex.
+default argument for ``num``, ``1``. If the second pattern matches,
+``page()`` will use whatever ``num`` value was captured.
Performance
===========
@@ -237,14 +319,14 @@ accessed. This makes the system blazingly fast.
Syntax of the ``urlpatterns`` variable
======================================
-``urlpatterns`` should be a Python list of :func:`~django.conf.urls.url`
-instances.
+``urlpatterns`` should be a Python list of :func:`~django.urls.path` and/or
+:func:`~django.urls.re_path` instances.
Error handling
==============
-When Django can't find a regex matching the requested URL, or when an
-exception is raised, Django will invoke an error-handling view.
+When Django can't find a match for the requested URL, or when an exception is
+raised, Django invokes an error-handling view.
The views to use for these cases are specified by four variables. Their
default values should suffice for most projects, but further customization is
@@ -277,39 +359,37 @@ essentially "roots" a set of URLs below other ones.
For example, here's an excerpt of the URLconf for the `Django website`_
itself. It includes a number of other URLconfs::
- from django.conf.urls import include, url
+ from django.urls import include, path
urlpatterns = [
# ... snip ...
- url(r'^community/', include('django_website.aggregator.urls')),
- url(r'^contact/', include('django_website.contact.urls')),
+ path('community/', include('aggregator.urls')),
+ path('contact/', include('contact.urls')),
# ... snip ...
]
-Note that the regular expressions in this example don't have a ``$``
-(end-of-string match character) but do include a trailing slash. Whenever
-Django encounters ``include()`` (:func:`django.conf.urls.include()`), it chops
-off whatever part of the URL matched up to that point and sends the remaining
+Whenever Django encounters :func:`~django.urls.include()`, it chops off
+whatever part of the URL matched up to that point and sends the remaining
string to the included URLconf for further processing.
Another possibility is to include additional URL patterns by using a list of
-:func:`~django.conf.urls.url` instances. For example, consider this URLconf::
+:func:`~django.urls.path` instances. For example, consider this URLconf::
- from django.conf.urls import include, url
+ from django.urls import include, path
from apps.main import views as main_views
from credit import views as credit_views
extra_patterns = [
- url(r'^reports/$', credit_views.report),
- url(r'^reports/(?P<id>[0-9]+)/$', credit_views.report),
- url(r'^charge/$', credit_views.charge),
+ path('reports/', credit_views.report),
+ path('reports/<int:id>/', credit_views.report),
+ path('charge/', credit_views.charge),
]
urlpatterns = [
- url(r'^$', main_views.homepage),
- url(r'^help/', include('apps.help.urls')),
- url(r'^credit/', include(extra_patterns)),
+ path('', main_views.homepage),
+ path('help/', include('apps.help.urls')),
+ path('credit/', include(extra_patterns)),
]
In this example, the ``/credit/reports/`` URL will be handled by the
@@ -318,28 +398,28 @@ In this example, the ``/credit/reports/`` URL will be handled by the
This can be used to remove redundancy from URLconfs where a single pattern
prefix is used repeatedly. For example, consider this URLconf::
- from django.conf.urls import url
+ from django.urls import path
from . import views
urlpatterns = [
- url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/history/$', views.history),
- url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/edit/$', views.edit),
- url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/discuss/$', views.discuss),
- url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/permissions/$', views.permissions),
+ path('<page_slug>-<page_id>/history/', views.history),
+ path('<page_slug>-<page_id>/edit/', views.edit),
+ path('<page_slug>-<page_id>/discuss/', views.discuss),
+ path('<page_slug>-<page_id>/permissions/', views.permissions),
]
We can improve this by stating the common path prefix only once and grouping
the suffixes that differ::
- from django.conf.urls import include, url
+ from django.urls import include, path
from . import views
urlpatterns = [
- url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/', include([
- url(r'^history/$', views.history),
- url(r'^edit/$', views.edit),
- url(r'^discuss/$', views.discuss),
- url(r'^permissions/$', views.permissions),
+ path('<page_slug>-<page_id>/', include([
+ path('history/', views.history),
+ path('edit/', views.edit),
+ path('discuss/', views.discuss),
+ path('permissions/', views.permissions),
])),
]
@@ -352,60 +432,24 @@ An included URLconf receives any captured parameters from parent URLconfs, so
the following example is valid::
# In settings/urls/main.py
- from django.conf.urls import include, url
+ from django.urls import include, path
urlpatterns = [
- url(r'^(?P<username>\w+)/blog/', include('foo.urls.blog')),
+ path('<username>/blog/', include('foo.urls.blog')),
]
# In foo/urls/blog.py
- from django.conf.urls import url
+ from django.urls import path
from . import views
urlpatterns = [
- url(r'^$', views.blog.index),
- url(r'^archive/$', views.blog.archive),
+ path('', views.blog.index),
+ path('archive/', views.blog.archive),
]
In the above example, the captured ``"username"`` variable is passed to the
included URLconf, as expected.
-Nested arguments
-================
-
-Regular expressions allow nested arguments, and Django will resolve them and
-pass them to the view. When reversing, Django will try to fill in all outer
-captured arguments, ignoring any nested captured arguments. Consider the
-following URL patterns which optionally take a page argument::
-
- from django.conf.urls import url
-
- urlpatterns = [
- url(r'blog/(page-(\d+)/)?$', blog_articles), # bad
- url(r'comments/(?:page-(?P<page_number>\d+)/)?$', comments), # good
- ]
-
-Both patterns use nested arguments and will resolve: for example,
-``blog/page-2/`` will result in a match to ``blog_articles`` with two
-positional arguments: ``page-2/`` and ``2``. The second pattern for
-``comments`` will match ``comments/page-2/`` with keyword argument
-``page_number`` set to 2. The outer argument in this case is a non-capturing
-argument ``(?:...)``.
-
-The ``blog_articles`` view needs the outermost captured argument to be reversed,
-``page-2/`` or no arguments in this case, while ``comments`` can be reversed
-with either no arguments or a value for ``page_number``.
-
-Nested captured arguments create a strong coupling between the view arguments
-and the URL as illustrated by ``blog_articles``: the view receives part of the
-URL (``page-2/``) instead of only the value the view is interested in. This
-coupling is even more pronounced when reversing, since to reverse the view we
-need to pass the piece of URL instead of the page number.
-
-As a rule of thumb, only capture the values the view needs to work with and
-use non-capturing arguments when the regular expression needs an argument but
-the view ignores it.
-
.. _views-extra-options:
Passing extra options to view functions
@@ -414,21 +458,21 @@ Passing extra options to view functions
URLconfs have a hook that lets you pass extra arguments to your view functions,
as a Python dictionary.
-The :func:`django.conf.urls.url` function can take an optional third argument
+The :func:`~django.urls.path` function can take an optional third argument
which should be a dictionary of extra keyword arguments to pass to the view
function.
For example::
- from django.conf.urls import url
+ from django.urls import path
from . import views
urlpatterns = [
- url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
+ path('blog/<int:year>/', views.year_archive, {'foo': 'bar'}),
]
In this example, for a request to ``/blog/2005/``, Django will call
-``views.year_archive(request, year='2005', foo='bar')``.
+``views.year_archive(request, year=2005, foo='bar')``.
This technique is used in the
:doc:`syndication framework </ref/contrib/syndication>` to pass metadata and
@@ -444,46 +488,45 @@ options to views.
Passing extra options to ``include()``
--------------------------------------
-Similarly, you can pass extra options to :func:`~django.conf.urls.include`.
-When you pass extra options to ``include()``, *each* line in the included
-URLconf will be passed the extra options.
+Similarly, you can pass extra options to :func:`~django.urls.include` and
+each line in the included URLconf will be passed the extra options.
For example, these two URLconf sets are functionally identical:
Set one::
# main.py
- from django.conf.urls import include, url
+ from django.urls import include, path
urlpatterns = [
- url(r'^blog/', include('inner'), {'blogid': 3}),
+ path('blog/', include('inner'), {'blog_id': 3}),
]
# inner.py
- from django.conf.urls import url
+ from django.urls import path
from mysite import views
urlpatterns = [
- url(r'^archive/$', views.archive),
- url(r'^about/$', views.about),
+ path('archive/', views.archive),
+ path('about/', views.about),
]
Set two::
# main.py
- from django.conf.urls import include, url
+ from django.urls import include, path
from mysite import views
urlpatterns = [
- url(r'^blog/', include('inner')),
+ path('blog/', include('inner')),
]
# inner.py
- from django.conf.urls import url
+ from django.urls import path
urlpatterns = [
- url(r'^archive/$', views.archive, {'blogid': 3}),
- url(r'^about/$', views.about, {'blogid': 3}),
+ path('archive/', views.archive, {'blog_id': 3}),
+ path('about/', views.about, {'blog_id': 3}),
]
Note that extra options will *always* be passed to *every* line in the included
@@ -543,18 +586,18 @@ Examples
Consider again this URLconf entry::
- from django.conf.urls import url
+ from django.urls import path
from . import views
urlpatterns = [
#...
- url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
+ path('articles/<int:year>/', views.year_archive, name='news-year-archive'),
#...
]
According to this design, the URL for the archive corresponding to year *nnnn*
-is ``/articles/nnnn/``.
+is ``/articles/<nnnn>/``.
You can obtain these in template code by using:
@@ -720,24 +763,24 @@ displaying polls.
.. snippet::
:filename: urls.py
- from django.conf.urls import include, url
+ from django.urls import include, path
urlpatterns = [
- url(r'^author-polls/', include('polls.urls', namespace='author-polls')),
- url(r'^publisher-polls/', include('polls.urls', namespace='publisher-polls')),
+ path('author-polls/', include('polls.urls', namespace='author-polls')),
+ path('publisher-polls/', include('polls.urls', namespace='publisher-polls')),
]
.. snippet::
:filename: polls/urls.py
- from django.conf.urls import url
+ from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
- url(r'^$', views.IndexView.as_view(), name='index'),
- url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
+ path('', views.IndexView.as_view(), name='index'),
+ path('<int:pk>/', views.DetailView.as_view(), name='detail'),
...
]
@@ -783,60 +826,61 @@ Application namespaces of included URLconfs can be specified in two ways.
Firstly, you can set an ``app_name`` attribute in the included URLconf module,
at the same level as the ``urlpatterns`` attribute. You have to pass the actual
-module, or a string reference to the module, to
-:func:`~django.conf.urls.include`, not the list of ``urlpatterns`` itself.
+module, or a string reference to the module, to :func:`~django.urls.include`,
+not the list of ``urlpatterns`` itself.
.. snippet::
:filename: polls/urls.py
- from django.conf.urls import url
+ from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
- url(r'^$', views.IndexView.as_view(), name='index'),
- url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
+ path('', views.IndexView.as_view(), name='index'),
+ path('<int:pk>/', views.DetailView.as_view(), name='detail'),
...
]
.. snippet::
:filename: urls.py
- from django.conf.urls import include, url
+ from django.urls import include, path
urlpatterns = [
- url(r'^polls/', include('polls.urls')),
+ path('polls/', include('polls.urls')),
]
The URLs defined in ``polls.urls`` will have an application namespace ``polls``.
Secondly, you can include an object that contains embedded namespace data. If
-you ``include()`` a list of :func:`~django.conf.urls.url` instances,
-the URLs contained in that object will be added to the global namespace.
-However, you can also ``include()`` a 2-tuple containing::
+you ``include()`` a list of :func:`~django.urls.path` or
+:func:`~django.urls.re_path` instances, the URLs contained in that object
+will be added to the global namespace. However, you can also ``include()`` a
+2-tuple containing::
- (<list of url() instances>, <application namespace>)
+ (<list of path()/re_path() instances>, <application namespace>)
For example::
- from django.conf.urls import include, url
+ from django.urls import include, path
from . import views
polls_patterns = ([
- url(r'^$', views.IndexView.as_view(), name='index'),
- url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
+ path('', views.IndexView.as_view(), name='index'),
+ path('<int:pk>/', views.DetailView.as_view(), name='detail'),
], 'polls')
urlpatterns = [
- url(r'^polls/', include(polls_patterns)),
+ path('polls/', include(polls_patterns)),
]
This will include the nominated URL patterns into the given application
namespace.
The instance namespace can be specified using the ``namespace`` argument to
-:func:`~django.conf.urls.include`. If the instance namespace is not specified,
+:func:`~django.urls.include`. If the instance namespace is not specified,
it will default to the included URLconf's application namespace. This means
it will also be the default instance for that namespace.
diff --git a/docs/topics/i18n/translation.txt b/docs/topics/i18n/translation.txt
index 148028c717..dcecbf61a5 100644
--- a/docs/topics/i18n/translation.txt
+++ b/docs/topics/i18n/translation.txt
@@ -992,15 +992,15 @@ The ``JavaScriptCatalog`` view
from django.views.i18n import JavaScriptCatalog
urlpatterns = [
- url(r'^jsi18n/$', JavaScriptCatalog.as_view(), name='javascript-catalog'),
+ path('jsi18n/', JavaScriptCatalog.as_view(), name='javascript-catalog'),
]
**Example with custom packages**::
urlpatterns = [
- url(r'^jsi18n/myapp/$',
- JavaScriptCatalog.as_view(packages=['your.app.label']),
- name='javascript-catalog'),
+ path('jsi18n/myapp/',
+ JavaScriptCatalog.as_view(packages=['your.app.label']),
+ name='javascript-catalog'),
]
If your root URLconf uses :func:`~django.conf.urls.i18n.i18n_patterns`,
@@ -1012,7 +1012,7 @@ The ``JavaScriptCatalog`` view
from django.conf.urls.i18n import i18n_patterns
urlpatterns = i18n_patterns(
- url(r'^jsi18n/$', JavaScriptCatalog.as_view(), name='javascript-catalog'),
+ path('jsi18n/', JavaScriptCatalog.as_view(), name='javascript-catalog'),
)
The precedence of translations is such that the packages appearing later in the
@@ -1235,9 +1235,9 @@ URL::
# The value returned by get_version() must change when translations change.
urlpatterns = [
- url(r'^jsi18n/$',
- cache_page(86400, key_prefix='js18n-%s' % get_version())(JavaScriptCatalog.as_view()),
- name='javascript-catalog'),
+ path('jsi18n/',
+ cache_page(86400, key_prefix='js18n-%s' % get_version())(JavaScriptCatalog.as_view()),
+ name='javascript-catalog'),
]
Client-side caching will save bandwidth and make your site load faster. If
@@ -1253,9 +1253,9 @@ whenever you restart your application server::
last_modified_date = timezone.now()
urlpatterns = [
- url(r'^jsi18n/$',
- last_modified(lambda req, **kw: last_modified_date)(JavaScriptCatalog.as_view()),
- name='javascript-catalog'),
+ path('jsi18n/',
+ last_modified(lambda req, **kw: last_modified_date)(JavaScriptCatalog.as_view()),
+ name='javascript-catalog'),
]
You can even pre-generate the JavaScript catalog as part of your deployment
@@ -1302,26 +1302,26 @@ translations to existing site so that the current URLs won't change.
Example URL patterns::
- from django.conf.urls import include, url
from django.conf.urls.i18n import i18n_patterns
+ from django.urls import include, url
from about import views as about_views
from news import views as news_views
from sitemap.views import sitemap
urlpatterns = [
- url(r'^sitemap\.xml$', sitemap, name='sitemap-xml'),
+ path('sitemap.xml', sitemap, name='sitemap-xml'),
]
news_patterns = ([
- url(r'^$', news_views.index, name='index'),
- url(r'^category/(?P<slug>[\w-]+)/$', news_views.category, name='category'),
- url(r'^(?P<slug>[\w-]+)/$', news_views.details, name='detail'),
+ path('', news_views.index, name='index'),
+ path('category/<slug>/', news_views.category, name='category'),
+ path('<slug>/', news_views.details, name='detail'),
], 'news')
urlpatterns += i18n_patterns(
- url(r'^about/$', about_views.main, name='about'),
- url(r'^news/', include(news_patterns, namespace='news')),
+ path('about/', about_views.main, name='about'),
+ path('news/', include(news_patterns, namespace='news')),
)
After defining these URL patterns, Django will automatically add the
@@ -1371,8 +1371,8 @@ Translating URL patterns
URL patterns can also be marked translatable using the
:func:`~django.utils.translation.gettext_lazy` function. Example::
- from django.conf.urls import include, url
from django.conf.urls.i18n import i18n_patterns
+ from django.urls import include, path
from django.utils.translation import gettext_lazy as _
from about import views as about_views
@@ -1380,18 +1380,18 @@ URL patterns can also be marked translatable using the
from sitemaps.views import sitemap
urlpatterns = [
- url(r'^sitemap\.xml$', sitemap, name='sitemap-xml'),
+ path('sitemap.xml', sitemap, name='sitemap-xml'),
]
news_patterns = ([
- url(r'^$', news_views.index, name='index'),
- url(_(r'^category/(?P<slug>[\w-]+)/$'), news_views.category, name='category'),
- url(r'^(?P<slug>[\w-]+)/$', news_views.details, name='detail'),
+ path('', news_views.index, name='index'),
+ path(_('category/<slug>/'), news_views.category, name='category'),
+ path('<slug>/', news_views.details, name='detail'),
], 'news')
urlpatterns += i18n_patterns(
- url(_(r'^about/$'), about_views.main, name='about'),
- url(_(r'^news/'), include(news_patterns, namespace='news')),
+ path(_('about/'), about_views.main, name='about'),
+ path(_('news/'), include(news_patterns, namespace='news')),
)
After you've created the translations, the :func:`~django.urls.reverse`
@@ -1750,7 +1750,7 @@ back to the previous page.
Activate this view by adding the following line to your URLconf::
- url(r'^i18n/', include('django.conf.urls.i18n')),
+ path('i18n/', include('django.conf.urls.i18n')),
(Note that this example makes the view available at ``/i18n/setlang/``.)