How does the Django routing layer get the correct URL

Time:2021-11-30
catalogue
  • preface
  • Tips – Django version differences
  • Route matching
  • Anonymous group & named group
    • Anonymous grouping
    • Named grouping
    • Tips
  • Reverse parsing
    • Routing does not involve reverse parsing of packets
    • Reverse parsing of named group & nameless group
  • Routing distribution

    preface

    When the client browser accesses the Django backend, it will first perform route matching in the routing layer through the gateway and middleware. Only after the route matching is successful can the logic in the corresponding view function be executed for data processing. This paper introduces 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 versions. One of the differences is the routing expression of the routing layer. The differences between the routing expressions are shown in the following table:

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

    If URL parameters are used to regular expressions, Django in versions 2. X and 3. X also provides another method re_ Path, which is equivalent to the path in Django 1. X.

    #Urls.py for django2. X
    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),
    ]

    Route matching

    Here, we use Django 1. X to explain how Django performs route matching? In Django 1. X, the correspondence between the route and the view is realized through the URL method, and the regular expression of the first parameter URL of the URL method. As long as the URL accessed by the client browser can successfully match a route, it will immediately stop the route after matching and directly execute the first matched view function, which will cause a problem, Such as the following code:

    urlpatterns = [
        url(r'test',views.test),
        url(r'testadd',views.testadd),
    ]
    
    #127.0.0.1:8080 / testadd will match the first route directly and will never run the following testadd page

    How to solve the above problems? You can specify what the regular expression of the route must start and end with, and the regular expression cannot be empty. Otherwise, it will match all URLs and make subsequent pages inaccessible. Therefore, the following solutions can be adopted when using the URL of the regular expression:

    urlpatterns = [
        #For the first page, the regular expression cannot be blank, otherwise it will match all URL suffixes, resulting in the inaccessibility of the following pages
        url(r'^$',views.home),
     #^ refers to what the matching character must start with and $refers to what the matching character must end with
        url(r'^test/$',views.test),
        url(r'testadd/',views.testadd),
    ]

    Anonymous group & named group

    First, what group? Grouping simply means to enclose a regular expression in parentheses. Nameless grouping simply means that the regular expression after grouping has no name, while famous grouping means that the regular expression after grouping has a name~ What a deep understanding…

    Anonymous grouping

    Anonymous grouping will pass the content matched by the regular expression in parentheses after grouping to the corresponding view function as a location parameter.

    # urls.py
    urlpatterns = [
        URL (r'test / (\ D +) ', views. Test), # \ D + indicates a matching number
    ]
    
    # views.py
    Def test (request, XX): # parameter XX can be arbitrary
        print(xx)
        return HttpResponse('test')

    If 127.0.0.1:8000 / test / 100 is accessed in the browser (the number can be arbitrary), 100 will be output in the pycharm terminal. If the formal parameter XX is not added to the view function test, an error will be reported. The error information is as follows:

    TypeError: test() takes 1 positional argument but 2 were given

    The test function has only one formal parameter, but it gives two arguments, so you must add one formal parameter to receive another argument. The other argument is what the regular expression in the nameless group matches.

    Named grouping

    This is to give an alias to the grouped regular expression, and pass the content matched by the regular expression in parentheses to the corresponding view function as a keyword parameter.

    # urls.py
    urlpatterns = [
        URL (r'test / (? P < ID > \ D +) ', views. Test), # \ D + represents the matching number, and ID is the name of the grouped regular expression
    ]
    
    # views.py
    Def test (request, ID): # when using a named group, the name of the formal parameter of the view function must be consistent with the name of the named group
        print(id)
        return HttpResponse('xx')

    If you access 127.0.0.1:8000 / test / 100 in the browser (the number can be arbitrary), 100 will be output in the pycharm terminal. If the name of the formal parameter in the view function test is inconsistent with the name of the famous group, an error will be reported. The error information is as follows:

    TypeError: test() got an unexpected keyword argument ‘id’

    The test function gets a keyword parameter ID that it doesn’t need. Therefore, when using a named group, the formal parameters of the view function must be consistent with the name of the named group.

    Tips

    Famous and nameless packets cannot be used at the same time, but each packet can be reused multiple times. At the same time, there must be a corresponding number of formal parameters in the view function to receive values.

    
    url(r'test/(\d+)/(\d+)/(\d+)',views.test)
    url(r'test/(?P<id1>\d+)/(?P<id2>\d+)/(?P<id3>\d+)', views.test)
    

    Reverse parsing

    The front-end browser sends a URL request. The URL will match to a view function responsible for the request (some parameters may be provided to the view function at the same time). This is a positive match.
    Starting from the alias of the view function binding relationship (some parameters may be required), the process of finding a complete URL is the reverse. The so-called resolution is to obtain a complete URL by adding some parameters to the alias (or the alias of the URL matching relationship or the alias of the URL pattern).

    Forward match: URL                  ——————————–>    View function (+ parameter)
    Reverse resolution: alias (parameter)   ———————————->   url

    The purpose of using reverse parsing is to obtain a URL in the front-end HTML page more conveniently, avoid hard coding and reduce the complexity of program maintenance. So how to use reverse parsing? Using reverse parsing is divided into two steps:
    ① Set an alias for the route in the route matching file urls.py;
    ② Use aliases in view functions or in HTML pages.

    The use of reverse resolution can also be divided into two cases: one is when the routing does not involve packets, and the other is the reverse resolution of famous packets and nameless packets.

    Routing does not involve reverse parsing of packets

    First, you need to set an alias for the correspondence between routing and view functions in urls.py. The code is as follows:

    urlpatterns = [
        re_path('index/', views.index, name='index'),
        re_ The path ('test / ', views. Test, name ='test') # route corresponds to the view function. The alias name is test. It can be arbitrary but must be unique
    ]

    After setting the alias of the corresponding relationship between the route and the view function, you can reverse parse it on the back-end or front-end HTML page and obtain the URL through the alias.

    #Views.py - reverse parsing in the back-end view function. Dynamic parsing needs to be realized with the help of modules
    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'))

    When the above code accesses 127.0.0.1:8000 / test /, it will be redirected through the test function, and the redirected URL is the index / route obtained by reverse parsing through the reverse method.

    Of course, on the front-end HTML page, you can also perform reverse parsing through the template syntax. Similarly, you can find the corresponding relationship through the alias, parse the URL, and then 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')
    
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <a href={% url 'index' %}>click me</a>  <!-- Resolve the back-end alias through the syntax format of {% URL 'alias'%}, and click to jump to index / route -- >
    </body>
    </html>

    Reverse parsing of named group & nameless group

    The reverse resolution of famous and nameless packets is somewhat different from that without grouping. The settings of the reverse resolution of famous and nameless packets in url.py are the same as those without grouping. They both use the parameter name to alias the corresponding relationship between routing and view functions, However, in the case of packets, not only the alias but also the data required in the regular expression packets need to be routed during reverse parsing. In the case of named packets, there are two ways to provide data during reverse parsing, both at the front end and at the back end, one of which is the common way of named packets and nameless packets.

    Let’s first look at the reverse parsing of anonymous groups:

    # urls.py
    urlpatterns = [
        re_path('index/(\d+)', views.index, name='index'),
        re_path('test/', views.test, name='test')
    ]
    
    -----------------------------------------Anonymous packet back-end reverse parsing-------------------------------
    #Views.py - back end reverse parsing
    def index(request, x):
        return HttpResponse('index')
    
    def test(request):
        #The parameter must be in the form of tuple, and the parameter must be able to match the grouping part in the regular expression, otherwise an error will be reported. Reverse for 'func' with no arguments not found. 1 pattern (s) tried: ['index / (\ \ D +)']
        return redirect(reverse(viewname='index', args=(1,))) 
    
    
    -----------------------------------------Anonymous packet 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 grouping matching parameter%}
    </body>

    Next, let’s look at the direction resolution of famous groups. There are two ways to implement the reverse resolution of famous groups. The first is consistent with the nameless group, and the other code is as follows:

    # urls.py
    urlpatterns = [
        re_path('index/(?P<id>\d+)', views.index, name='index'),
        re_path('test/', views.test, name='test')
    ]
    
    ----------------------------------------Name group reverse parsing - back end reverse parsing-----------------------
    # views.py
    def index(request, id):
        return HttpResponse('index')
    
    def test(request):
        #The parameter matching the name group is the format of the dictionary. The key of the dictionary is the name of the name group
        return redirect(reverse(viewname='index', kwargs={'id': 2}))
    
    --------------------------------------Name group reverse parsing - front end reverse parsing-------------------------
    # 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 name group name = group matching parameter%} 
    </body>

    Routing distribution

    Each application of Django can have its own urls.py/templates folder / static folder. Based on this, Django can achieve group development very well. Everyone can only write the application part they are responsible for. So how can different applications be integrated together? You only need to copy all applications to a new Django project (we’ll talk about it later in Git collaborative development…) then register all applications in the configuration file, and finally integrate all applications with routing distribution, * * routing distribution is to identify which application the current URL belongs to, and then directly distribute it to the corresponding application for further processing** To use route distribution, you need to create urls.py under each application, which is called sub route. The original urls.py is called general route. For example, two applications are created in a Django project, first and second. Route distribution can be realized in the following ways:

    ----------------------------Sub route file---------------------------------------------------
    #Urls.py under first application - 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),
    ]
    
    #Urls.py under second application - 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),
    ]
    
    -----------------------------------------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))
    ]

    After using route distribution, access the URL under different applications. The route must indicate which application the route belongs to. For example, access 127.0.0.1:8000 / first / test, which means to reach the general route through the first for route distribution, and then match the test / part in the first application. When the total route is used for route distribution, the regular expression parameter of URL () cannot end with $, but must end with /.

    The above general routing file also has a simplified version of code, which directly includes the sub route string without importing the sub route, as follows:

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

    This is the end of this article on how to get the correct URL for Django routing layer. For more information about how to get the URL for Django routing layer, please search the previous articles of developeppaer or continue to browse the relevant articles below. I hope you will support developeppaer in the future!