May 14, 2021 Django
2. Django is how to handle a request
5. Register a custom path converter
8. Specify the default value for the view parameters
10.. In the syntax urlpatterns variable
13.. Pass additional options to view the function
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 .
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.
When a user requests a page from your Django-supported website, the following algorithm is used to determine the Python code to execute:
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:
Example of a request:
By default, the following path converters are available:
For more complex matching requirements, you can define your own path converter.
A converter is a class that contains the following:
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),
...
]
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:
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.
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.
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.
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
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.
Each regular expression in urlpatterns is compiled on the first visit. This makes the system run very fast.
urlpatterns should be a sequence of path() and/or re_path () instances.
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:
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 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.
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.
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.
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:
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:
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.
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 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:
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'.
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:
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.
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 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.
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/