This article is participating in Python Theme Month. See the link to the event for more details

Rest cannot be enjoyed by lazy people.~

preface

When the client browser accesses the Django backend through the gateway and middleware, it will first perform route matching at the routing layer. Only after the route matching is successful can it perform the corresponding logic in the view function to process the data. This article will describe how the routing layer (taking Diango1.x version as an example) performs route matching.

Tips – Django version differences

There are some differences between django1.x and Django2.x and later. One of the differences is the routing expressions at the routing layer. The differences between routing expressions are shown in the following table:

The difference between django1.x django2.x or 3.x
methods Url methodfrom django.conf.urls import url The path methodfrom django.urls import path
The url parameter The first argument supports regular expressions The first argument does not support regular expressions

If regular expressions are used for url arguments, the 2.x and 3.x versions of Django also provide another method, re_path, which is equivalent to the path in django1.x.

# django2.x version of urls.py
from django.contrib import admin
from django.urls import path,re_path
from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('index',views.index),
    re_path('^index/\d+',views.index),
]
Copy the code

Routing matching

Here we use django1.x to show how Django does route matching. In django1.x, the mapping between routes and views is implemented through the URL method. The first parameter of the URL method is the regular expression of the URL. As long as the URL accessed by the client browser matches a route successfully, it immediately stops the subsequent route matching and directly executes the first matched view function. This creates a problem like the following code:

urlpatterns = [
    url(r'test',views.test),
    url(r'testadd',views.testadd),
]

# 127.0.0.1:8080/ testAdd will directly match the first route and will never run the following testAdd page
Copy the code

How to solve these problems? The regular expression that can be specified must start with and end with something. The regular expression cannot be empty. Otherwise, all urls are matched and subsequent pages cannot be accessed.

urlpatterns = [
    # Home page, regular expression cannot be blank, otherwise all url suffixes will be matched, resulting in the subsequent pages cannot be accessed
    url(r'^$',views.home),
	# ^ is what the matching character must begin with. $is what the matching character must end with
    url(r'^test/$',views.test),
    url(r'testadd/',views.testadd),
]
Copy the code

Anonymous group & named group

What are the groups first? Grouping simply means enclosing a regular expression in parentheses. An anonymous group simply means that the regular expression after the group has no name, while a named group means that the regular expression after the group has a name. ~ What a profound understanding…

Unknown group

An anonymous group will pass the contents matched by the regular expression in parentheses after the grouping to the corresponding view function as positional arguments.

# urls.py
urlpatterns = [
    url(r'test/(\d+)', views.test),   # \d+ indicates the matching number
]

# views.py
def test(request, xx) :  The # parameter xx can be arbitrary
    print(xx)
    return HttpResponse('test')
Copy the code

If you access 127.0.0.1:8000/test/100(the number can be arbitrary) in your browser, you will output 100 in pyCharm’s terminal, and if you do not add xx to the view function test, you will get an error. The error message is as follows:

TypeError: test() takes 1 positional argument but 2The "were given" function has only one parameter but is given two arguments, so one parameter must be added to accept the other. The other argument is what the regular expression matches in the unnamed group.Copy the code

Famous group

It aliases the grouped regular expression and passes the matching contents of the regular expression in parentheses to the corresponding view function as keyword arguments.

# urls.py
urlpatterns = [
    url(r'test/(? P
      
       \d+)'
      ,views.test),   # \d+ indicates the matching number, and id is the name of the group's regular expression
]

# views.py
def test(request, id) :  When using named groups, the parameter names of the view functions must be the same as the names of the named groups
    print(id)
    return HttpResponse('xx')
Copy the code

If you access 127.0.0.1:8000/test/100(the number can be arbitrary) in your browser, the pyCharm terminal will output 100. If the parameter name in the test view function does not match the name of the named group, the error message will be as follows:

TypeError: test() got an unexpected keyword argument 'id'The test function gets a keyword argument that it does not needid. Therefore, when using a named group, the parameters of the view function must match the name of the named group.Copy the code

tip

Named and unnamed groups cannot be used at the same time, but each group can be used multiple times, and there must be a corresponding number of parameters in the view function to receive values.

url(r'test/(\d+)/(\d+)/(\d+)',views.test)
url(r'test/(? P
      
       \d+)/(? P
       
        \d+)/(? P
        
         \d+)'
        , views.test)
Copy the code

Reverse DNS

The front end browser sends a URL request that matches a view function that is responsible for the request (and may also give some parameters to the view function). This is a forward match.

The process of finding a complete URL is reversed, starting with the alias of the view function binding (which may take some parameters). Parsing is the process of obtaining a complete URL by using the alias (or the alias of the URL matching relationship, or the alias of the URl-pattern) plus some parameters.

Positive match: url — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — > view function parameters (+)

Reverse DNS: alias (parameters) — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — > url

The purpose of using reverse parsing is to make it easier to get a URL in a front-end HTML page, avoiding hard coding and reducing the complexity of program maintenance. So how do you use reverse resolution? There are two steps to using reverse parsing:

① Set aliases for routes in the routing matching file urls.py;

Use aliases in view functions or in HTML pages.

There are two cases in which reverse resolution is used. One is when routing does not involve packets, and the other is when nameless and named packets are reversed.

Routes do not involve reverse packet resolution

You first need to set aliases for the routing and view functions in urls.py, as follows:

urlpatterns = [
    re_path('index/', views.index, name='index'),
    re_path('test/', views.test, name='test') The alias name of the route to the view function is test, which can be arbitrary, but must be unique
]  
Copy the code

After you set the alias of the route and view function, you can reverse parse the back end or front end HTML page, using the alias to get the URL.

# views.py - reverse parsing in the back-end view function, with the help of modules to achieve dynamic parsing
from django.shortcuts import render, redirect, HttpResponse, reverse


# Create your views here.
def index(request) :
    return HttpResponse('index')


def test(request) :
    return redirect(reverse('index'))
Copy the code

When accessing 127.0.0.1:8000/test/, the code will redirect through the test function, and the URL is the index/ route obtained through reverse resolution.

Of course, in the front end of the HTML page can also be reversed parsing operations through the template syntax, also through the alias to find the corresponding relationship after parsing out the URL to execute the corresponding view function.

# views.py
from django.shortcuts import render, redirect, HttpResponse


# Create your views here.
def index(request) :
    return HttpResponse('index')


def test(request) :
    return render(request, 'render_html.html')
Copy the code
<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<a href={% url 'index' %}>click me</a>  <! {% url 'alias' %} {% url' alias' %}
</body>
</html>
Copy the code

Reverse resolution of named groups & anonymous groups

The reverse lookup of named and anonymous groups is a little different from that of ungrouped groups. The reverse lookup of named and anonymous groups is set in url.py in the same way that it is set when there is no grouping. However, in the case of groups, the reverse lookup not only provides aliases but also routes the data needed in the regular expression groups. In the case of named groups, there are two ways to provide data in the reverse lookup, both front end and back end. One of the ways is shared by named groups and nameless groups.

First look at the reverse resolution of an anonymous group:

# urls.py
urlpatterns = [
    re_path('index/(\d+)', views.index, name='index'),
    re_path('test/', views.test, name='test')] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - unknown group backend reverse DNS -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -# views.py - reverse lookup on the back end
def index(request, x) :
    return HttpResponse('index')

def test(request) :
    # Reverse for 'func' with no arguments not found. 1 Pattern (s) : ['index/(\\d+)']
    return redirect(reverse(viewname='index', args=(1,))) -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - unknown group front-end reverse parsing -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --# views.py
def index(request, x) :
    return HttpResponse('index')

def test(request) :
    return render(request, 'render_html.html')

# render_html.html
<body>
<a href={% url 'index' 1 %}>click me</a>   # {% URL alias group matching parameter %}
</body>
Copy the code

There are two ways to reverse resolve named groups. The first is the same as the nameless group. The other code is as follows:

# urls.py
urlpatterns = [
    re_path('index/(? P
      
       \d+)'
      , views.index, name='index'),
    re_path('test/', views.test, name='test')] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- famous grouping reverse DNS - backend reverse DNS -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --# views.py
def index(request, id) :
    return HttpResponse('index')

def test(request) :
    The key of the dictionary is the name of the named group
    return redirect(reverse(viewname='index', kwargs={'id': 2})) -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- famous grouping reverse DNS - front reverse DNS -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --# views.py
def index(request, id) :
    return HttpResponse('index')

def test(request) :
    return render(request, 'render_html.html')

# render_html.html
<body>
<a href={% url 'index' id=2 %}>click me</a>  # {% url alias group name = group matching parameter %}
</body>
Copy the code

Routing distribution

Each django application can have its own urls.py/templates folder /static folder. Because of this, Django works very well for group development, with each person writing their own part of the application. Just copy all the applications into a new Django project (more on git co-development later…) Then, all applications are registered in the configuration file and all applications are integrated by route distribution. ** Route distribution is to identify which application belongs to the current URL and directly distribute the URL to the corresponding application for further processing. ** To use routing distribution, you need to create a urls.py under each application called a child route, and the original urls.py is called a total route. For example, a Django project creates two applications called First and second. Routing distribution can be done as follows:

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- zi lu by the file -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -# first app urls.py - first_django/first/urls.py
from django.conf.urls import url
from first import views

urlpatterns = [
    url(r'^index/', views.index),
    url(r'^test/', views.test),
]

# second app urls.py - first_django/second/urls.py
from django.conf.urls import url
from second import views

urlpatterns = [
    url(r'^index/', views.index),
    url(r'^test/', views. Test),] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - the total routing file -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --# first_django/first_django/urls.py
from django.conf.urls import url,include
from django.contrib import admin
from firstp import urls as first_url
from second import urls as second_url

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^first/',include(first_url)),
    url(r'^second/',include(second_url))
]
Copy the code

After using distributed routing, access to the application of different url routing must be said in the chain by which belongs to the application, such as access to 127.0.0.1:8000 / first/test, said first routed through the first to reach the total route distribution and then in the first application in the test/parts matching. When the total route is used to distribute routes, the regular expression parameter of URL () cannot end with $, but must end with /.

There is also a simplified version of the routing file that does not need to import the child route. Include the child route string as follows:

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - the total routing file -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --# first_django/first_django/urls.py
from django.conf.urls import url,include
from django.contrib import admin
# from firstp import urls as first_url
# from second import urls as second_url

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^first/',include('first.urls')),
    url(r'^second/',include('first.urls')))Copy the code

conclusion

The article was first published on the wechat official account ** “Cheng Xuyuan Xiaozhuang” **, and synchronously published in Digijin.

Please explain where it came from. If you pass by, please put out your cute little finger and click like before you go (╹▽╹)