Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Django processes HTTP requests


May 14, 2021 Django


Table of contents


URL scheduling

Clean, elegant URL solutions are important details in high-quality Web applications. Django allows you to design URLs as needed without framework restrictions.

For a great argument in the article "Cool URIs not not not change" by World Wide Web creator Tim Berners-Lee on why URLs should be clean and available, see .

Overview

To design the URL of your application, you can create a Python module informally called URLconf (URL configuration). The module is pure Python code and is a mapping between the URL path expression and the Python function (your view).

The map can be short or long as needed. I t can reference other maps. And because it's pure Python code, it can be built dynamically.

Django also provides a way to translate URLs according to the active language. For more information, see the Internationalization documentation.

Django is how to handle a request

When a user requests a page from your Django-supported website, the following algorithm is used to determine the Python code to execute:

  1. Django determines which root URLLconf module to use. Typically, this ROOT_URLCONF the value set, but if the incoming HttpRequest object has the urlconf property (set by the middleware), its value is used instead of the ROOT_URLCONF setting.
  2. Django loads the Python module and looks for the variable urlpatterns. This should be a sequence of django.urls.path() and/django.urls.re_path () instances.
  3. Django traverses each URL pattern sequentially and stops at the first URL that matches the requested URL, which matches the path_info.
  4. Once one of the URL patterns matches, Django imports and calls the given view, which is a Python function (or class-based view). T he view passes the following parameters: the instance httpRequest. I f the matching URL pattern does not contain a named group, matches from the regular expression are provided as positional parameters. K eyword parameters consist of any named part of the provided path expression match, which is overwritten by any parameter specified in the optional kwargs parameter of or . Django.urls.path() django.urls.re_path() was changed in Django 3.0: in older versions, keyword parameters with None values were also made up of named parts that were not provided.
  5. Django calls an appropriate error handling view if there is no URL pattern match, or if an exception is thrown at any time during this process. See error handling below.

Example

This is an example of 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 a URL, use angle brackets.
  • The captured value can be selected to include the converter type. F or example, used to 'capture integer parameters.' If the converter/'is is not included, any string other than the character is matched.
  • There is no need to add a slash, as each URL has that slash. For example, articles, not / articles.

Example of a request:

  • Request/articles/2005/03/match the third entry in the list. D jango will call the function. views.month_archive(request, year=2005, month=3)
  • /articles/2003/matches the first pattern in the list, not the second, because these patterns are tested sequentially, and the first one is the first test to pass. F eel free to use commands to insert special situations like this. Here, Django calls the function views.special_case_2003 (request)
  • /articles/2003 does not match any of these patterns because each mode requires the URL to end with a slash.
  • /articles/2003/03/building-a-django-site/will match the final pattern. D jango will call the function. views.article_detail(request, year=2003, month=3, slug="building-a-django-site")

The path converter

By default, the following path converters are available:

  • Str- matches any non-empty strings except the path separator '/'. If the converter is not included in the expression, it is the default setting.
  • int-match zero or any positive integer. Return to int.
  • slug- matches any bar string consisting of ASCII letters or numbers, as well as hyphens and underscore characters. For example, building-your-1st-django-site.
  • uuid-match formatted UUID. T o prevent multiple URLs from mapping to the same page, dashes must be included and letters must be lowercase. F or example, 075194d3-6885-417e-a8a8-6c931e272f00. Returns a UUID instance.
  • path- matches any non-empty string, including the path separator '/'. This allows you to match the full URL path instead of matching a portion of the URL path as if it were str.

Register a custom path converter

For more complex matching requirements, you can define your own path converter.

A converter is a class that contains the following:

  • A regex class property, as a string.
  • A method for converting matching strings to types that should be passed to view functions. I f a given value cannot be converted, it should be filled. A is interpreted as a mismatch, and the resulting 404 response is sent to the user unless another URL pattern matches. to_python(self, value)``ValueError``ValueError
  • One way to convert the Python type to a string to use in the URL. to_url(self, value)

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 register_converter converter class in URLconf using the following command:

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),
  ...
]

Use regular expressions

Regular expressions can also be used if the path and converter syntax are not sufficient to define the URL pattern. To do this, use re_path () instead of path().

In Python regular expressions, the syntax for naming a group of regular expressions is (? Ppattern), where the name of the group is the name of the group, and pattern is a pattern that matches.

This is the previous example, URLconf, overrides 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 does much the same thing as in the previous example, except:

  • The exact URL to be matched is more limited. For example, the year 10000 will no longer match because the year integer is limited to exactly four digits long.
  • Regardless of which match the regular expression is made, each captured argument is sent to the view as a string.

When switching from using path(), re_path() and vice versa, it is particularly important to note that the type of view parameters may change, so you may need to adjust the view.

Use an unnamed regular expression group

In addition to naming group syntax (for example) (? You can also use shorter unnamed groups {4} (e.g.) (0-9) {4}).

This usage is not recommended because it makes it easier to accidentally introduce errors between the expected meaning of the match and the parameters of the view.

In either case, it is recommended to use only one style in a given regular expression. When the two styles are mixed, any unnamed groups are ignored and only named groups are passed to the view function.

Nested parameters

Regular expressions allow nested parameters, which Django parses and passes to the view. W hen reversing, Django attempts to fill in all externally captured parameters, ignoring any nested capture parameters. Consider the following URL patterns, which can choose to use the page parameters:

from django.urls import re_path

urlpatterns = [
  re_path(r'^blog/(page-(\d+)/)?$', blog_articles),                 # bad
  re_path(r'^comments/(?:page-(?P<page_number>\d+)/)?$', comments), # good
]

Both modes use nested parameters and will resolve: for example, blog/page-2/will result in two positional parameters that match the blog_articles: page-2/and 2. T he second mode of comments matches the commons/page-2/with the keyword page_number to 2. In this case, the external parameter is a non-captured parameter (?:...).

The blog_articles view needs the parameters captured by the outerm to be reversed, page-2/or in this case does not need parameters, and the view comments can be reversed without parameters or values page_number.

Nested capture parameters establish a strong coupling between view parameters and URLs, as follows blog_articles the view receives a partial URL (page-2/) instead of just receiving values of interest to the view. This inverse is more obvious when reversing, because inverse views, we need to pass the URL instead of the page number.

As a rule of law, when a regular expression requires parameters but the view ignores them, only the values that the view needs to use are captured and non-captured parameters are used.

What URLconf searched for

URLconf searches for the requested URL according to the normal Python string. This does not include GET or POST parameters or domain names.

For example, in a request https://www.example.com/myapp/,URLconf will look for myapp/.

In the request https://www.example.com/myapp/?page=3,URLconf will look for myapp/.

URLconf does not view the request method. I n other words, all request methods - , POST, etc. - will be routed to the same URL with the same functionality. GET``HEAD

Specify the default value for the view parameters

A handy trick is to specify the default parameters for the parameters of the view. Here is an example URLLconf 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 example above, both URL patterns point to the same view - views.page - but the first mode does not capture anything from the URL. I f the first pattern matches, the page() function uses its default argument num, 1. If the second pattern matches, page() uses any value captured by num.

Performance

Each regular expression in urlpatterns is compiled on the first visit. This makes the system run very fast.

In the syntax urlpatterns variable

urlpatterns should be a sequence of path() and/or re_path () instances.

Error handling

Django calls the error-handling view when it cannot find a match for the requested URL or throws an exception.

The view used in these cases is specified by four variables. Their default values are sufficient for most projects, but they can be further customized by overwriting their default values.

For full details, see the documentation for custom error views.

You can set these values in your root URLLconf. Setting these variables in any other URLconf will not be valid.

The value must be callable, or a string representing the view's full Python import path, and the view should be called to handle the current error situation.

The variables are:

Includes other URLconf

At any time, you can "include" other URLconf modules. Essentially, this "roots" the URL under the other URLs.

For example, this is an excerpt from the DJango website itself, URLconf. It includes many other URLconf:

from django.urls import include, path

urlpatterns = [
  # ... snip ...
  path('community/', include('aggregator.urls')),
  path('contact/', include('contact.urls')),
  # ... snip ...
]

Whenever Django encounters include(), it truncated any part of the URL that matches until that point in time and sends the remaining string to the included URLLconf for further processing.

Another possibility is to include other URL patterns by using the path() instance list. For example, consider the following 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, /credit/reports/URL will be handled credit_views.report() Django view.

This can be used to remove redundancy from URLconf that reuses a single pattern prefix. For example, consider the following 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 declaring the public path prefix only once and grouping the different suffixes:

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),
    ])),
]

The parameters of the snap

The included URLconf receives any captured parameters from the parent URLLconfs, 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 example above, the captured "username" variable is passed as expected to the included URLconf.

Pass additional options to view the function

URLconfs has a hook that allows you to pass additional parameters to the view function as a Python dictionary.

The path() function can use an optional third argument, which should be a dictionary of additional keyword parameters passed 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, Django will call for requests/blogs/2005/. views.year_archive(request, year=2005, foo='bar')

This technique is used in the federation framework to pass metadata and options to the view.

Deal with conflicts

URL patterns may capture named keyword parameters and pass parameters with the same name in their extra parameters dictionary. When this happens, the parameters in the dictionary are used instead of the parameters captured in the URL.

Pass additional options to include()

Similarly, you can pass additional options to include(), and each line in the included URLLconf passes the additional options.

For example, the 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),
]

Setting 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 the additional options are always passed to each row in the included URLLconf, regardless of whether the view of the row actually accepts these options. Therefore, this technique is useful only if you determine that each view in the included URLconf accepts the additional options to pass.

Reverse resolution of the URL

When working on a Django project, it is often necessary to obtain the final form of URL to embed the generated content (view and asset URL, URL displayed to the user, etc.) or to work on the side of the navigation process on the server (redirect, etc.)

There is a strong desire to avoid hard coding of these URLs (a laborive, non-scalable, and error-prone strategy). Equally dangerous is the design of temporary mechanisms to generate URLs parallel to the design described by URLconf, which can cause the generation of URLs to become stale over time.

In other words, a DRY mechanism is required. Among other advantages, it allows the development of URL design without having to traverse all project source code to search for and replace outdated URLs.

The main information we can get about a URL is the identity (such as the name) of the view that handles it. The type (location, keywords) and values of the view parameters must also contain additional information in the correct URL lookup.

Django provides a solution that makes the URL mapptor the only repository for URL design. You provide it with URLconf, and you can then use it in two directions:

  • Starting with the URL requested by the user/browser, it calls the correct Django view to provide any parameters that may be required and the values extracted from the URL.
  • Get the associated URL, starting with identifying the corresponding Django view and the parameter values that will be passed to the view.

The first is the usage we discussed in the last section. The second is the so-called URL reverse resolution, reverse URL matching, reverse URL lookup or simply URL reverse.

Django provides tools for performing URL reversals that match the different layers that require URLs:

  • In the template: Mark with the url template.
  • In Python code: Use the reverse() function.
  • Advanced code related to URL processing for Django model instances: get_absolute_url () method.

Example

Consider the following URLconf entries again:

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 NNNN corresponding to the annual archive is /articles//.

You can get them using the following template code:

<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 you decide to change the URL of the archived content of the published annual article, you only need to change the entry in URLconf.

In some cases where the view is of a general nature, there may be a many-to-one relationship between the URL and the view. I n these cases, the view name is not a good enough identifier when reversing the URL. Read the next section to learn about Django's solution for this.

Name the URL mode

In order to perform the URL reverse, you need to use the named URL pattern, as in the example above. T he string used by the URL name can contain any character you like. You are not limited to valid Python names.

When naming URL mode, select a name that is unlikely to conflict with the name of other applications. If the URL mode is called and the other application does the same thing, the URL found by reverse() depends on the last pattern in the project urlpatterns list.

Adding a prefix to your URL name, which may originate from an application name, such as myapp-comment instead of general, reduces the chance of conflict.

If you want to overwrite the view, you can deliberately select the same URL name as another application. F or example, a common use case is to override LoginView. S ome parts of Django and most third-party applications assume that this view has a URL mode login with the name. If you have a custom login view and give it the URL name login, reverse() will find the custom view as long as it is included (if it is included in all) after the urlpatterns django.contrib.auth.urls.

You can also use the same name if the parameters of multiple URL patterns are different. In addition to the URL name, reverse() matches the number of parameters and the name of the keyword parameters.

The URL namespace

Brief introduction

The URL namespace allows you to uniquely reverse-name the URL pattern, even if different applications use the same URL name. F or third-party applications, it's a good habit to always use the URL of the namespace (as we did in this tutorial). S imilarly, if multiple instances of an application are deployed, it also allows you to reverse the URL. In other words, because multiple instances of a single application will share named URLs, namespaces provide a way to distinguish between these named URLs.

For a particular site, you can use the Django application that uses the URL namespace correctly multiple times. F or example, django.contrib.admin has an AdminSite class that allows you to deploy multiple admin instances. In the next example, we'll discuss the idea of deploying polling applications from tutorials in two different locations so that we can provide the same functionality for two different audiences (authors and publishers).

The URL namespace is divided into two parts, both strings:

  • The application namespace describes the name of the application being deployed. E ach instance of a single application will have the same application namespace. For example, Django's admin application has a predictable application namespace 'admin'.
  • The instance namespace identifies a specific instance of the application. T he instance namespace should be unique throughout the project. H owever, the instance namespace can be the same as the application namespace. T his is used to specify the default instance of the application. For example, the default Django management instance has an instance namespace of 'admin'.

Use the ':' operator to specify a URL separated by name. F or example, use the main index page 'admin:index' of the reference management application. This represents the namespace 'admin', as well as the name URL 'index'.

Namespaces can also be nested. The named URL 'sports:polls:index' will look for the pattern 'index' named in the namespace, which itself is defined in the top-level namespace 'sports'.

The URL of the reverse namespace

Given the namespace URL (for example) to be resolved by 'polls:index', Django splits the fully qualified name into parts, and then tries the following lookup:

  1. First, Django looks for a matching application namespace ('polls' in this example). This results in a list of instances of the application.
  2. If the current application is defined, Django finds and returns the URL parser for the instance. Y ou can use the current_app of the function to specify the current application, reverse(). T he url template label uses the current resolution view in the current application's namespace RequestContext. You can override request.current_app by setting the current application on the property of the property.
  3. If there is no current application, Django looks for the default application instance. The default application instance is a namespace that has that instance instance namespace matching app (in this example, an instance of polls is called 'polls').
  4. If there is no default application instance, Django selects the last deployment instance for the application, regardless of its name.
  5. If the namespace provided in step 1 does not match the application namespace, Django will try to find the namespace directly as the instance namespace.

If there is a nested namespace, repeat these steps for each part of the namespace until only the view name is resolved. The view name is then resolved to the URL found in the namespace.

Example

To demonstrate the practical effect of the solution, consider an example of two instances of the application in this tutorial: one called 'author-polls' and one called 'publisher-polls'. Let's say we've enhanced the application to take the instance namespace into account when creating and displaying polls.

the 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')),
]

Poll/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'),
    ...
]

With this setting, you can look for the following:

  • If one of the instances is the current-that is, if we are drawing the instance details page 'author-polls'-'polls:index' resolves to the index page 'author-polls' instance; T hat is, the following two will result in "/author-polls/". In a class-based view approach: reverse ('polls:index', current_app=self.request.resolver_match.namespace) and in the template: '% url 'polls:index' %)
  • If there is no current instance (for example, if we are rendering a page elsewhere on the site), 'polls:index' will resolve to the last registered instance polls. B ecause there is no default instance (the instance namespace 'polls'), polls will use the last instance of that instance. This is 'publisher-polls' because it is declared as the last urlpatterns.
  • 'author-polls:index' will always resolve to the instance's index page 'author-polls'.

If there is still a default instance (that is, an instance named 'polls'), the only change is that there is no current instance (the second item in the list above). In this case, 'polls:index' resolves to the index page of the default instance, not the last instance declared in urlpatterns.

URL namespace and included URLconf

There are two ways to specify the application namespace that contains URLconf.

First, you app_name to set the same level of properties as the urlpatterns property in the included URLLconf module. You must pass the actual module or a string reference to the module to include(), not its own list of urlpatterns.

Poll/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'),
    ...
]

the urls.py

from django.urls import include, path

urlpatterns = [
    path('polls/', include('polls.urls')),
]

The URL polls.urls defined in will have an application namespace polars.

Second, you can include an object that contains embedded namespace data. I f you include() list path() re_path() instances, the URL contained in the object is added to the global namespace. However, you can also include() contain a 2-dollar group that contains the following:

(<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 includes the nominated URL pattern in a given application namespace.

You can use the namespace parameter to specify the instance namespace include(). I f the instance namespace is not specified, it defaults to the included URLconf application namespace. This means that it will also be the default instance of the namespace.

For more information: https://docs.djangoproject.com/en/3.0/topics/http/urls/