123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913 |
- ==============
- URL dispatcher
- ==============
- A clean, elegant URL scheme is an important detail in a high-quality web
- application. Django lets you design URLs however you want, with no framework
- limitations.
- See `Cool URIs don't change`_, by World Wide Web creator Tim Berners-Lee, for
- excellent arguments on why URLs should be clean and usable.
- .. _Cool URIs don't change: https://www.w3.org/Provider/Style/URI
- 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
- 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
- dynamically.
- Django also provides a way to translate URLs according to the active
- language. See the :ref:`internationalization documentation
- <url-internationalization>` for more information.
- .. _how-django-processes-a-request:
- How Django processes a request
- ==============================
- When a user requests a page from your Django-powered site, this is the
- algorithm the system follows to determine which Python code to execute:
- #. Django determines the root URLconf module to use. Ordinarily,
- this is the value of the :setting:`ROOT_URLCONF` setting, but if the incoming
- ``HttpRequest`` object has a :attr:`~django.http.HttpRequest.urlconf`
- attribute (set by middleware), its value will be used in place of the
- :setting:`ROOT_URLCONF` setting.
- #. Django loads that Python module and looks for the variable
- ``urlpatterns``. This should be a :term:`sequence` of
- :func:`django.urls.path` and/or :func:`django.urls.re_path` instances.
- #. Django runs through each URL pattern, in order, and stops at the first
- one that matches the requested URL, matching against
- :attr:`~django.http.HttpRequest.path_info`.
- #. Once one of the URL patterns matches, Django imports and calls the given
- view, which is a 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 URL pattern contained no named groups, then the
- matches from the regular expression are provided as positional arguments.
- * The keyword arguments are made up of any named parts matched by the
- path expression that are provided, overridden by any arguments specified
- in the optional ``kwargs`` argument to :func:`django.urls.path` or
- :func:`django.urls.re_path`.
- #. 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.
- Example
- =======
- Here's a sample URLconf::
- from django.urls import path
- from . import views
- urlpatterns = [
- 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:slug>/", views.article_detail),
- ]
- Notes:
- * To capture a value from the URL, use angle brackets.
- * 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.
- * 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, 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
- is the first test to pass. Feel free to exploit the ordering to insert
- special cases like this. Here, Django would call the function
- ``views.special_case_2003(request)``
- * ``/articles/2003`` would not match any of these patterns, because each
- pattern requires that the URL end with a slash.
- * ``/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. To prevent multiple URLs from mapping to
- the same page, dashes must be included and letters must be lowercase. 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
- 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 ``ValueError`` is
- interpreted as no match and as a consequence a 404 response is sent to the
- user unless another URL pattern matches.
- * A ``to_url(self, value)`` method, which handles converting the Python type
- into a string to be used in the URL. It should raise ``ValueError`` if it
- can't convert the given value. A ``ValueError`` is interpreted as no match
- and as a consequence :func:`~django.urls.reverse` will raise
- :class:`~django.urls.NoReverseMatch` unless another URL pattern matches.
- 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 path, register_converter
- from . import converters, views
- register_converter(converters.FourDigitYearConverter, "yyyy")
- urlpatterns = [
- path("articles/2003/", views.special_case_2003),
- path("articles/<yyyy:year>/", views.year_archive),
- ...,
- ]
- .. deprecated:: 5.1
- Overriding existing converters with ``django.urls.register_converter()`` is
- deprecated.
- 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 example URLconf from earlier, rewritten using regular expressions::
- from django.urls import path, re_path
- from . import views
- urlpatterns = [
- path("articles/2003/", views.special_case_2003),
- re_path(r"^articles/(?P<year>[0-9]{4})/$", views.year_archive),
- re_path(r"^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$", views.month_archive),
- re_path(
- r"^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$",
- views.article_detail,
- ),
- ]
- 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 a given regex is recommended. When
- both styles are mixed, any unnamed groups are ignored and only named groups are
- passed to the view function.
- 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.urls import re_path
- urlpatterns = [
- re_path(r"^blog/(page-([0-9]+)/)?$", blog_articles), # bad
- re_path(r"^comments/(?:page-(?P<page_number>[0-9]+)/)?$", 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.
- What the URLconf searches against
- =================================
- The URLconf searches against the requested URL, as a normal Python string. This
- does not include GET or 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 look
- for ``myapp/``.
- 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.
- Specifying defaults for view arguments
- ======================================
- A convenient trick is to specify default parameters for your views' arguments.
- Here's an example URLconf and view::
- # URLconf
- from django.urls import path
- from . import views
- urlpatterns = [
- path("blog/", views.page),
- path("blog/page<int:num>/", views.page),
- ]
- # View (in blog/views.py)
- 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.
- Performance
- ===========
- Django processes regular expressions in the ``urlpatterns`` list which is
- compiled the first time it's accessed. Subsequent requests use the cached
- configuration via the URL resolver.
- Syntax of the ``urlpatterns`` variable
- ======================================
- ``urlpatterns`` should be a :term:`sequence` of :func:`~django.urls.path`
- and/or :func:`~django.urls.re_path` instances.
- Error handling
- ==============
- 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
- possible by overriding their default values.
- See the documentation on :ref:`customizing error views
- <customizing-error-views>` for the full details.
- Such values can be set in your root URLconf. Setting these variables in any
- other URLconf will have no effect.
- Values must be callables, or strings representing the full Python import path
- to the view that should be called to handle the error condition at hand.
- The variables are:
- * ``handler400`` -- See :data:`django.conf.urls.handler400`.
- * ``handler403`` -- See :data:`django.conf.urls.handler403`.
- * ``handler404`` -- See :data:`django.conf.urls.handler404`.
- * ``handler500`` -- See :data:`django.conf.urls.handler500`.
- .. _including-other-urlconfs:
- Including other URLconfs
- ========================
- At any point, your ``urlpatterns`` can "include" other URLconf modules. This
- 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.urls import include, path
- urlpatterns = [
- # ... snip ...
- path("community/", include("aggregator.urls")),
- path("contact/", include("contact.urls")),
- # ... snip ...
- ]
- 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.urls.path` instances. For example, consider this URLconf::
- from django.urls import include, path
- from apps.main import views as main_views
- from credit import views as credit_views
- extra_patterns = [
- path("reports/", credit_views.report),
- path("reports/<int:id>/", credit_views.report),
- path("charge/", credit_views.charge),
- ]
- urlpatterns = [
- 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
- ``credit_views.report()`` Django view.
- This can be used to remove redundancy from URLconfs where a single pattern
- prefix is used repeatedly. For example, consider this URLconf::
- from django.urls import path
- from . import views
- urlpatterns = [
- 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.urls import include, path
- from . import views
- urlpatterns = [
- path(
- "<page_slug>-<page_id>/",
- include(
- [
- path("history/", views.history),
- path("edit/", views.edit),
- path("discuss/", views.discuss),
- path("permissions/", views.permissions),
- ]
- ),
- ),
- ]
- .. _`Django website`: https://www.djangoproject.com/
- Captured parameters
- -------------------
- An included URLconf receives any captured parameters from parent URLconfs, so
- the following example is valid::
- # In settings/urls/main.py
- from django.urls import include, path
- urlpatterns = [
- path("<username>/blog/", include("foo.urls.blog")),
- ]
- # In foo/urls/blog.py
- from django.urls import path
- from . import views
- urlpatterns = [
- 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.
- .. _views-extra-options:
- 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.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.urls import path
- from . import views
- urlpatterns = [
- 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')``.
- This technique is used in the
- :doc:`syndication framework </ref/contrib/syndication>` to pass metadata and
- options to views.
- .. admonition:: Dealing with conflicts
- It's possible to have a URL pattern which captures named keyword arguments,
- and also passes arguments with the same names in its dictionary of extra
- arguments. When this happens, the arguments in the dictionary will be used
- instead of the arguments captured in the URL.
- Passing extra options to ``include()``
- --------------------------------------
- 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.urls import include, path
- urlpatterns = [
- path("blog/", include("inner"), {"blog_id": 3}),
- ]
- # inner.py
- from django.urls import path
- from mysite import views
- urlpatterns = [
- path("archive/", views.archive),
- path("about/", views.about),
- ]
- Set two::
- # main.py
- from django.urls import include, path
- from mysite import views
- urlpatterns = [
- path("blog/", include("inner")),
- ]
- # inner.py
- from django.urls import path
- urlpatterns = [
- 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
- URLconf, regardless of whether the line's view actually accepts those options
- as valid. For this reason, this technique is only useful if you're certain that
- every view in the included URLconf accepts the extra options you're passing.
- Reverse resolution of URLs
- ==========================
- A common need when working on a Django project is the possibility to obtain URLs
- in their final forms either for embedding in generated content (views and assets
- URLs, URLs shown to the user, etc.) or for handling of the navigation flow on
- the server side (redirections, etc.)
- It is strongly desirable to avoid hard-coding these URLs (a laborious,
- non-scalable and error-prone strategy). Equally dangerous is devising ad-hoc
- mechanisms to generate URLs that are parallel to the design described by the
- URLconf, which can result in the production of URLs that become stale over time.
- In other words, what's needed is a DRY mechanism. Among other advantages it
- would allow evolution of the URL design without having to go over all the
- project source code to search and replace outdated URLs.
- The primary piece of information we have available to get a URL is an
- identification (e.g. the name) of the view in charge of handling it. Other
- pieces of information that necessarily must participate in the lookup of the
- right URL are the types (positional, keyword) and values of the view arguments.
- Django provides a solution such that the URL mapper is the only repository of
- the URL design. You feed it with your URLconf and then it can be used in both
- directions:
- * Starting with a URL requested by the user/browser, it calls the right Django
- view providing any arguments it might need with their values as extracted from
- the URL.
- * Starting with the identification of the corresponding Django view plus the
- values of arguments that would be passed to it, obtain the associated URL.
- The first one is the usage we've been discussing in the previous sections. The
- second one is what is known as *reverse resolution of URLs*, *reverse URL
- matching*, *reverse URL lookup*, or simply *URL reversing*.
- Django provides tools for performing URL reversing that match the different
- layers where URLs are needed:
- * In templates: Using the :ttag:`url` template tag.
- * In Python code: Using the :func:`~django.urls.reverse` function.
- * In higher level code related to handling of URLs of Django model instances:
- The :meth:`~django.db.models.Model.get_absolute_url` method.
- Examples
- --------
- Consider again this URLconf entry::
- from django.urls import path
- from . import views
- urlpatterns = [
- # ...
- 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>/``.
- You can obtain these in template code by using:
- .. code-block:: html+django
- <a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
- {# Or with the year in a template context variable: #}
- <ul>
- {% for yearvar in year_list %}
- <li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
- {% endfor %}
- </ul>
- Or in Python code::
- from django.http import HttpResponseRedirect
- from django.urls import reverse
- def redirect_to_year(request):
- # ...
- year = 2006
- # ...
- return HttpResponseRedirect(reverse("news-year-archive", args=(year,)))
- If, for some reason, it was decided that the URLs where content for yearly
- article archives are published at should be changed then you would only need to
- change the entry in the URLconf.
- In some scenarios where views are of a generic nature, a many-to-one
- relationship might exist between URLs and views. For these cases the view name
- isn't a good enough identifier for it when comes the time of reversing
- URLs. Read the next section to know about the solution Django provides for this.
- .. _naming-url-patterns:
- Naming URL patterns
- ===================
- In order to perform URL reversing, you'll need to use **named URL patterns**
- as done in the examples above. The string used for the URL name can contain any
- characters you like. You are not restricted to valid Python names.
- When naming URL patterns, choose names that are unlikely to clash with other
- applications' choice of names. If you call your URL pattern ``comment``
- and another application does the same thing, the URL that
- :func:`~django.urls.reverse()` finds depends on whichever pattern is last in
- your project's ``urlpatterns`` list.
- Putting a prefix on your URL names, perhaps derived from the application
- name (such as ``myapp-comment`` instead of ``comment``), decreases the chance
- of collision.
- You can deliberately choose the *same URL name* as another application if you
- want to override a view. For example, a common use case is to override the
- :class:`~django.contrib.auth.views.LoginView`. Parts of Django and most
- third-party apps assume that this view has a URL pattern with the name
- ``login``. If you have a custom login view and give its URL the name ``login``,
- :func:`~django.urls.reverse()` will find your custom view as long as it's in
- ``urlpatterns`` after ``django.contrib.auth.urls`` is included (if that's
- included at all).
- You may also use the same name for multiple URL patterns if they differ in
- their arguments. In addition to the URL name, :func:`~django.urls.reverse()`
- matches the number of arguments and the names of the keyword arguments. Path
- converters can also raise ``ValueError`` to indicate no match, see
- :ref:`registering-custom-path-converters` for details.
- .. _topics-http-defining-url-namespaces:
- URL namespaces
- ==============
- Introduction
- ------------
- URL namespaces allow you to uniquely reverse :ref:`named URL patterns
- <naming-url-patterns>` even if different applications use the same URL names.
- It's a good practice for third-party apps to always use namespaced URLs (as we
- did in the tutorial). Similarly, it also allows you to reverse URLs if multiple
- instances of an application are deployed. In other words, since multiple
- instances of a single application will share named URLs, namespaces provide a
- way to tell these named URLs apart.
- Django applications that make proper use of URL namespacing can be deployed
- more than once for a particular site. For example :mod:`django.contrib.admin`
- has an :class:`~django.contrib.admin.AdminSite` class which allows you to
- :ref:`deploy more than one instance of the admin <multiple-admin-sites>`. In a
- later example, we'll discuss the idea of deploying the polls application from
- the tutorial in two different locations so we can serve the same functionality
- to two different audiences (authors and publishers).
- A URL namespace comes in two parts, both of which are strings:
- .. glossary::
- application namespace
- This describes the name of the application that is being deployed. Every
- instance of a single application will have the same application namespace.
- For example, Django's admin application has the somewhat predictable
- application namespace of ``'admin'``.
- instance namespace
- This identifies a specific instance of an application. Instance namespaces
- should be unique across your entire project. However, an instance namespace
- can be the same as the application namespace. This is used to specify a
- default instance of an application. For example, the default Django admin
- instance has an instance namespace of ``'admin'``.
- Namespaced URLs are specified using the ``':'`` operator. For example, the main
- index page of the admin application is referenced using ``'admin:index'``. This
- indicates a namespace of ``'admin'``, and a named URL of ``'index'``.
- Namespaces can also be nested. The named URL ``'sports:polls:index'`` would
- look for a pattern named ``'index'`` in the namespace ``'polls'`` that is itself
- defined within the top-level namespace ``'sports'``.
- .. _topics-http-reversing-url-namespaces:
- Reversing namespaced URLs
- -------------------------
- When given a namespaced URL (e.g. ``'polls:index'``) to resolve, Django splits
- the fully qualified name into parts and then tries the following lookup:
- #. First, Django looks for a matching :term:`application namespace` (in this
- example, ``'polls'``). This will yield a list of instances of that
- application.
- #. If there is a current application defined, Django finds and returns the URL
- resolver for that instance. The current application can be specified with
- the ``current_app`` argument to the :func:`~django.urls.reverse()`
- function.
- The :ttag:`url` template tag uses the namespace of the currently resolved
- view as the current application in a
- :class:`~django.template.RequestContext`. You can override this default by
- setting the current application on the :attr:`request.current_app
- <django.http.HttpRequest.current_app>` attribute.
- #. If there is no current application, Django looks for a default
- application instance. The default application instance is the instance
- that has an :term:`instance namespace` matching the :term:`application
- namespace` (in this example, an instance of ``polls`` called ``'polls'``).
- #. If there is no default application instance, Django will pick the last
- deployed instance of the application, whatever its instance name may be.
- #. If the provided namespace doesn't match an :term:`application namespace` in
- step 1, Django will attempt a direct lookup of the namespace as an
- :term:`instance namespace`.
- If there are nested namespaces, these steps are repeated for each part of the
- namespace until only the view name is unresolved. The view name will then be
- resolved into a URL in the namespace that has been found.
- Example
- ~~~~~~~
- To show this resolution strategy in action, consider an example of two instances
- of the ``polls`` application from the tutorial: one called ``'author-polls'``
- and one called ``'publisher-polls'``. Assume we have enhanced that application
- so that it takes the instance namespace into consideration when creating and
- displaying polls.
- .. code-block:: python
- :caption: ``urls.py``
- from django.urls import include, path
- urlpatterns = [
- path("author-polls/", include("polls.urls", namespace="author-polls")),
- path("publisher-polls/", include("polls.urls", namespace="publisher-polls")),
- ]
- .. code-block:: python
- :caption: ``polls/urls.py``
- from django.urls import path
- from . import views
- app_name = "polls"
- urlpatterns = [
- path("", views.IndexView.as_view(), name="index"),
- path("<int:pk>/", views.DetailView.as_view(), name="detail"),
- ...,
- ]
- Using this setup, the following lookups are possible:
- * If one of the instances is current - say, if we were rendering the detail page
- in the instance ``'author-polls'`` - ``'polls:index'`` will resolve to the
- index page of the ``'author-polls'`` instance; i.e. both of the following will
- result in ``"/author-polls/"``.
- In the method of a class-based view::
- reverse("polls:index", current_app=self.request.resolver_match.namespace)
- and in the template:
- .. code-block:: html+django
- {% url 'polls:index' %}
- * If there is no current instance - say, if we were rendering a page
- somewhere else on the site - ``'polls:index'`` will resolve to the last
- registered instance of ``polls``. Since there is no default instance
- (instance namespace of ``'polls'``), the last instance of ``polls`` that is
- registered will be used. This would be ``'publisher-polls'`` since it's
- declared last in the ``urlpatterns``.
- * ``'author-polls:index'`` will always resolve to the index page of the instance
- ``'author-polls'`` (and likewise for ``'publisher-polls'``) .
- If there were also a default instance - i.e., an instance named ``'polls'`` -
- the only change from above would be in the case where there is no current
- instance (the second item in the list above). In this case ``'polls:index'``
- would resolve to the index page of the default instance instead of the instance
- declared last in ``urlpatterns``.
- .. _namespaces-and-include:
- URL namespaces and included URLconfs
- ------------------------------------
- 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.urls.include`,
- not the list of ``urlpatterns`` itself.
- .. code-block:: python
- :caption: ``polls/urls.py``
- from django.urls import path
- from . import views
- app_name = "polls"
- urlpatterns = [
- path("", views.IndexView.as_view(), name="index"),
- path("<int:pk>/", views.DetailView.as_view(), name="detail"),
- ...,
- ]
- .. code-block:: python
- :caption: ``urls.py``
- from django.urls import include, path
- urlpatterns = [
- 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.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:
- .. code-block:: text
- (<list of path()/re_path() instances>, <application namespace>)
- For example::
- from django.urls import include, path
- from . import views
- polls_patterns = (
- [
- path("", views.IndexView.as_view(), name="index"),
- path("<int:pk>/", views.DetailView.as_view(), name="detail"),
- ],
- "polls",
- )
- urlpatterns = [
- 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.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.
|