Django (xvi) Case-based login template: Log decorator, csrf attack and protection, Post wording of csrf ajax opening, generates a verification code, add code to sign, the reverse resolution mass participation +

A, csrf attack

1.1 csrf attack (CSRF)

[Namely] csrf attack: through third-party websites, request forgery (provided that you are logged normal site, and save the session cookie or login information and not withdrawn), third-party site can be modified directly or through your session cookie username password normal website.
Here Insert Picture Description

  1. First, do a login page, allowing users to enter a user name and password, log on after the jump successfully changed your password page. In the Change Password page, enter a new password, click the OK button to complete the password change.
  2. Logon page requires a template file login.html. Change Password pages also need a template file change_pwd.html.
  3. Show View login login page, verify view login_check logged in to post a display view change_pwd page, change the password handling view change_pwd_action.
  4. Additional functions:
    A) can be modified cryptographic operations only after the user logs on.
  5. Login decorator function (app2 / views.py):
def login_required(view_func): #参数即调用它的函数
    '''登录判断装饰器'''
    def wrapper(request, *view_args, **view_kwargs): # 内部函数,包装一下
        # 判断用户是否登录
        if request.session.has_key('islogin'): #如果登录了,就返回真正页面(调用此装饰器函数的函数)
            # 用户已登录,调用对应的视图
            return view_func(request, *view_args, **view_kwargs)
        else:
            # 否则,用户未登录,则跳转到登录页
            return redirect('/login')
    return wrapper
  1. Login decorative calls, such as a page must be logged in to operation, or jump to the login page
    [app2 / views.py]@login_required
# /change_pwd
@login_required #作用:把此页面作为一个参数传到login_required里
def change_pwd(request):
    '''显示修改密码页面'''
    return render(request, 'booktest/change_pwd.html')

[Examples] csrf attack to change your password (must be logged in to post operation):

1) project2 / settings.py commented csrf

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
   # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

2)templates/change_pwd.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>修改密码页面</title>
</head>
<body>
<form method="post" action="/change_pwd_action/">
    新密码:<input type="password" name="pwd">
    <input type="submit" value="确认修改">
</form>
</body>
</html>

3) app2 / views.py [Login decorator]

[1] Log decorators: the user is logged in, the corresponding view call; the user is not logged in, jump to the login page
[2] need to log in to operate the call log on page decorator
[3] need to be logged in to operate the call log on page decoration device

from django.shortcuts import render,redirect
from django.template import loader,RequestContext
from django.http import HttpResponse,JsonResponse
from app2.models import BookInfo

def login(request):
    '''登录页'''
    # 判断用户是否登录,用户已登录, 直接跳转到图书列表
    if request.session.has_key('islogin'):
        return redirect('/change_pwd/')
    else:
        #如果用户名密码已经在cookie中,则取到它,并做为参数返回给渲染页面
        if 'username' in request.COOKIES:
            #获取cookie中的用户名、密码
            username=request.COOKIES['username']
            #password=request.COOKIES['password']

        else:
            username=''
            password=''
    return render(request,'app2/login.html',{'username':username,'password':password})


def login_check(request):
    '''登录校验'''
    #1.获取用户名密码
    username=request.POST.get('username')
    password=request.POST.get('password')
    remember=request.POST.get('remember') #接收remeber
    #2.进行校验,并返回json数据
    if username=='jim' and password=='123':
        #return redirect('/books')
        response = JsonResponse({'res':1}) #正确返回1,重写

        #如果remember==on,则把用户名,密码设置cookie到cookie
        if remember=='on':
            #response.set_cookie('username',username,max_age=7*24*3600)
            #response.set_cookie('password',password,max_age=7*24*3600)
            # 记住用户登录状态把用户名设置到session
            request.session['username'] = username
            # 返回应答
            # 如果用户勾选了remember的条件下,设置session,记住用户登录状态
            request.session['islogin'] = True # 只有session中有islogin,就认为用户已登录
        return response #不要忘记返回response
    else:
        #return redirect('/login')
        return JsonResponse({'res':0}) #错误返回0

#【1】登录装饰器:用户已登录,调用对应的视图;用户未登录,跳转到登录页
def login_required(view_func):
    '''登录判断装饰器'''
    def wrapper(request, *view_args, **view_kwargs):
        # 判断用户是否登录
        if request.session.has_key('islogin'):
            # 用户已登录,调用对应的视图
            return view_func(request, *view_args, **view_kwargs)
        else:
            # 用户未登录,跳转到登录页
            return redirect('/login')
    return wrapper


# /change_pwd
@login_required #【2】需要登录才能操作的页面调用登录装饰器
def change_pwd(request):
    '''显示修改密码页面'''
    # # 进行用户是否登录的判断
    # if not request.session.has_key('islogin'):
    #     # 用户未登录,跳转到登录
    #     return redirect('/login')

    return render(request, 'app2/change_pwd.html')


# /change_pwd_action
@login_required #【3】需要登录才能操作的页面调用登录装饰器
def change_pwd_action(request):
    '''模拟修改密码处理'''
    # # 进行用户是否登录的判断
    # if not request.session.has_key('islogin'):
    #     # 用户未登录,跳转到登录
    #     return redirect('/login')

    # 1.获取新密码
    pwd = request.POST.get('pwd')
    # 获取用户名
    username = request.session.get('username')
    # 2.实际开发的时候: 修改对应数据库中的内容...
    # 3.返回一个应答
    return HttpResponse('%s修改密码为:%s'%(username,pwd))

4)app2/urls.py

    path('login/',views.login),#登录页
    path('login_check',views.login_check),#登录检测
    
    path('change_pwd/', views.change_pwd), # 修改密码页面显示
    path('change_pwd_action/', views.change_pwd_action), # 修改密码处理

5) templates / login.html (ajax login technology)

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <!-- 【0】引入jquery -->
    <script src="/static/js/jquery-1.12.4.min.js"></script>
    <title>登录页面</title>
</head>
<script>
    // 写ajax处理函数
    $(function () {
        $('#btnLogin').click(function () {
            //1.获取用户名、密码、是否记住用户名
            username=$('#username').val()
            password=$('#password').val()
            remember=$('#remember').val() //【2】是否记住用户名
            //2.发起ajax--post(username,password)请求验证,地址:/login_check
            $.ajax({
                'url':'/login_check',//验证地址
                'type':'post',//请求类型
                'data':{'username':username,'password':password,'remember':remember},//【3】发送数据,加上remember
                'dataType':'json',//希望返回数据类型
            }).success(function(data){
                //成功返回{'res':1},失败{'res':0}
                if(data.res===0){
                    $('#msg').show().html('用户名或密码错误请重试!')//登录失败则显示msg,并在里写入信息
                }else{//成功跳转到books页面
                    location.href='/change_pwd'
                }
            })

        })
    })
</script>
<style>
    /* 信息提示样式 */
#msg{
    display: none;
    color:red;
}
</style>
<body>
    <!-- 原form删除,input的name变id,方便jquery操作 -->
    <!-- 【4】把views页的login()函数传过来的用户名,密码赋值给对应处 -->
    用户名:<input type="text" id="username" value="{{username}}"><br/>
    密码:<input type="password" id="password" value="{{password}}"><br/>
    <!-- 加入一个信息提示框,用于密码等错误提示 -->
    <div id="msg"></div>
    <!-- 【1】记住用户名,设置cookie用,如果勾选则其value=on -->
    <input type="checkbox" id="remember">记住用户名<br/>
    <!-- 按钮type改button,加一个id方便jquery操作 -->
    <input type="button" id="btnLogin" value="登录">

</body>
</html>

6) the effect of: http: //127.0.0.1: 8000 / login /

wrong user name or password:

Here Insert Picture Description

Direct access to change the password without logging page: http: //127.0.0.1: 8000 / change_pwd jump back to the login page
u / p correctly (jim, 123) Jump to: http: //127.0.0.1: 8000 / change_pwd

Here Insert Picture Description
Then Tip: jim change the password as follows: 456

7) Modify procedure follows the specific code via a third party website:

  1. First check to access the server's LAN IP and public IP
ipconfig /all
找到:
192.168.1.4

公网直接百度IP,查看即可
  1. Create a service, the following 2-to-1
如果在局域网创建服务:
py manage.py runserver 192.168.1.4:8000

如果在【虚拟机】或【真正服务器】创建服务:
py manage.py runserver 公网IP:8000
  1. Configuration settings.py
DEBUG = False #True
ALLOWED_HOSTS = ['*']
  1. In another computer to access the LAN: 192.168.1.4: 8000 / login to access the site, enter (jim, 123) login is successful.
  2. [Create] self a fake page to access the computer in the following page:
    [csrf-test.html]
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>修改密码页面</title>
</head>
<body>
<form method="post" action="http://192.168.1.4:8000/change_pwd_action/">
    <input type="hidden" name="pwd" value='789'><!--【1】用了隐藏input,页面只能看到一个按钮,并给新密码定为789-->
    <input type="submit" value="点我有惊喜!">
</form>
</body>
</html>
  1. Open the pages of step 5, the key point to the success of the corresponding Web site to modify the password:
    Here Insert Picture Description
  2. Cross-site request forgery post modify user password success!
jim修改密码为:789

1.1.1 django prevent csrf way:

1) by default csrf middleware (project2 / settings.py).

[1] django csrf protection turned on by default, it is only effective for post submission

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware', #【1】django默认打开csrf防护,它只对post提交有效
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

2) plus post when submitting the form data {% csrf_token %}tag

(Corresponding to the template in this example: change_pwd.html).
[Note]: need a post page pages submitted must add {% csrf_token %}, or even visit the site page will fail.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>修改密码页面</title>
</head>
<body>
<form method="post" action="/change_pwd_action/">
    {% csrf_token %}<!--【1】本页面要有post提交,所以加上-->
    新密码:<input type="password" name="pwd">
    <input type="submit" value="确认修改">
</form>
</body>
</html>

3) templates / app2 / login.html is Ajax page, so you can not use longhand

【参考】:https://code.ziqiangxuetang.com/django/django-csrf.html?bd_source_light=4317393

  1. Use render in the view (rather than render_to_response)
  2. Ajax in Canada:
$.ajaxPost({
    data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});
  1. Detailed code: [4] Protection csrf
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <!-- 【0】引入jquery -->
    <script src="/static/js/jquery-1.12.4.min.js"></script>
    <title>登录页面</title>
</head>

<script>
    // 写ajax处理函数
    $(function () {
        $('#btnLogin').click(function () {
            //1.获取用户名、密码、是否记住用户名
            username=$('#username').val()
            password=$('#password').val()
            remember=$('#remember').val() //【2】是否记住用户名
            //2.发起ajax--post(username,password)请求验证,地址:/login_check
            $.ajax({
                'url':'/login_check',//验证地址
                'type':'post',//请求类型
                'data':{//【3】发送数据,加上remember
                    'username':username,
                    'password':password,
                    'remember':remember,
                    csrfmiddlewaretoken: '{{ csrf_token }}',//【4】csrf防护
                    },
                'dataType':'json',//希望返回数据类型
            }).success(function(data){
                //成功返回{'res':1},失败{'res':0}
                if(data.res===0){
                    $('#msg').show().html('用户名或密码错误请重试!')//登录失败则显示msg,并在里写入信息
                }else{//成功跳转到books页面
                    location.href='/change_pwd'
                }
            })

        })
    })
</script>
<style>
    /* 信息提示样式 */
#msg{
    display: none;
    color:red;
}
</style>
<body>
    <!-- 原form删除,input的name变id,方便jquery操作 -->
    <!-- 【4】把views页的login()函数传过来的用户名,密码赋值给对应处 -->
    用户名:<input type="text" id="username" value="{{username}}"><br/>
    密码:<input type="password" id="password" value="{{password}}"><br/>
    <!-- 加入一个信息提示框,用于密码等错误提示 -->
    <div id="msg"></div>
    <!-- 【1】记住用户名,设置cookie用,如果勾选则其value=on -->
    <input type="checkbox" id="remember">记住用户名<br/>
    <!-- 按钮type改button,加一个id方便jquery操作 -->
    <input type="button" id="btnLogin" value="登录">

</body>
</html>

And then cross-site modification (7.6):

<p style="background-color:rgb(255, 255, 204)">
禁止访问 (403)
CSRF验证失败. 请求被中断.
您看到此消息是由于该站点在提交表单时需要一个CSRF cookie。此项是出于安全考虑,以确保您的浏览器没有被第三方劫持。
If you have configured your browser to disable cookies, please re-enable them, at least for this site, or for “same-origin” requests.</p>

1.1.2 Defense principle:

1) 渲染模板文件时在页面生成一个名字叫做csrfmiddlewaretoken的隐藏域。
在网站右键查看源码,可看到这个隐藏域:name=csrfmiddlewaretoken 的input

<form method="post" action="/change_pwd_action/">
    <input type="hidden" name="csrfmiddlewaretoken" value="O6lfnrybooqSP9Je0bZyCOr8qGObvK0jgzV7fMUW259X117OkpAm8OjtCsadu9tk">
    新密码:<input type="password" name="pwd">
    <input type="submit" value="确认修改">
</form>

把上例的隐藏域的value传给服务器。

 <input type="hidden" name="csrfmiddlewaretoken" value="O6lfnrybooqSP9Je0bZyCOr8qGObvK0jgzV7fMUW259X117OkpAm8OjtCsadu9tk">

2) 服务器同时交给浏览器保存一个名字为csrftoken的cookie信息。
3) 提交表单时,两个值都会发给服务器,服务器进行比对,如果一样,则csrf验证通过,否则失败。

二、验证码

  • 在用户注册、登录页面,为了防止暴力请求(穷举法破解用户名密码、自动注册大量账号等),可以加入验证码功能,如果验证码错误,则不需要继续处理,可以减轻业务服务器、数据库服务器的压力。
  • 【其它生成验证码参考】:https://blog.csdn.net/ding_312/article/details/82258442

    1)生成验证码函数 app2/views.py

    【1】存入session,用于做进一步验证
    【2】将图片保存在内存中,文件类型为png
    【3】将内存中的图片数据返回给客户端,MIME类型为图片png
from PIL import Image, ImageDraw, ImageFont
import io

# /verify_code
def verify_code(request):
    # 引入随机函数模块
    import random
    # 定义变量,用于画面的背景色、宽、高 RGB
    bgcolor = (random.randrange(20, 100), random.randrange(20, 100), 255)
    width = 100
    height = 25
    # 创建画面对象
    im = Image.new('RGB', (width, height), bgcolor)
    # 创建画笔对象
    draw = ImageDraw.Draw(im)
    # 调用画笔的point()函数绘制噪点
    for i in range(0, 100):
        xy = (random.randrange(0, width), random.randrange(0, height))
        fill = (random.randrange(0, 255), 255, random.randrange(0, 255))
        draw.point(xy, fill=fill)

    # 定义验证码的备选值
    str1 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0' #qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789
    # 随机选取4个值作为验证码
    rand_str = ''
    for i in range(0, 4):
        rand_str += str1[random.randrange(0, len(str1))]

    # 构造字体对象,ubuntu的字体路径为“/usr/share/fonts/truetype/freefont”
    font = ImageFont.truetype('AdobeFanHeitiStd-Bold.otf', 23)
    # 构造字体颜色
    fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255))
    # 绘制4个字
    draw.text((5, 2), rand_str[0], font=font, fill=fontcolor)
    draw.text((25, 2), rand_str[1], font=font, fill=fontcolor)
    draw.text((50, 2), rand_str[2], font=font, fill=fontcolor)
    draw.text((75, 2), rand_str[3], font=font, fill=fontcolor)
    # 释放画笔
    del draw
    # 【1】存入session,用于做进一步验证
    request.session['verifycode'] = rand_str
    # 内存文件操作
    buf = io.BytesIO()
    # 【2】将图片保存在内存中,文件类型为png
    im.save(buf, 'png')
    # 【3】将内存中的图片数据返回给客户端,MIME类型为图片png
    return HttpResponse(buf.getvalue(), 'image/png')

2)app2/urls.py

path('verify_code',views.verify_code),#生成验证码

3)效果:http://127.0.0.1:8000/verify_code

Here Insert Picture Description

4)在templates/app2/login.html加验证码(这次用表单提交)

【1】添加验证码,直接把验证码地址写在src内

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
<form method="post" action="/login_check">
    {% csrf_token %}
    用户名:<input type="text" name="username" value="{{ username }}"><br/>
    密码:<input type="password" name="password"><br/>
    <input type="checkbox" name="remember">记住用户名<br/>
    <!--【1】添加验证码,直接把地址写在src内-->
    <img src="/verify_code"><br/>
    <input type="text" name="vcode">输入验证码<br/>
    <input type="submit" value="登录">
</form>
</body>
</html>

5)app2/views.py验证函数修改

【1】获取用户输入验证码
【2】获取session中保存的验证码(在第1步)
【3】进行验证码校验,如果验证码输入不对直接返回登录页面,下面的密码验证就不再进行操作了

def login(request):
    '''登录页'''
    # 判断用户是否登录,用户已登录, 直接跳转到图书列表
    if request.session.has_key('islogin'):
        return redirect('/change_pwd/')
    else:
        #如果用户名密码已经在cookie中,则取到它,并做为参数返回给渲染页面
        if 'username' in request.COOKIES:
            #获取cookie中的用户名、密码
            username=request.COOKIES['username']
            #password=request.COOKIES['password']

        else:
            username=''
            #password=''
    return render(request,'app2/login.html',{'username':username}) #,'password':password


def login_check(request):
    '''登录校验'''
    #1.获取用户名密码
    username=request.POST.get('username')
    password=request.POST.get('password')
    remember=request.POST.get('remember') #接收remeber
    
    vcode1 = request.POST.get('vcode') # 【1】获取用户输入验证码
    vcode2 = request.session.get('verifycode') # 【2】获取session中保存的验证码
    # 【3】进行验证码校验,如果验证码输入不对直接返回登录页面,下面的密码验证就不再进行操作了
    if vcode1 != vcode2:
        # 验证码错误
        return redirect('/login')

    #2.进行校验,并返回json数据
    if username=='jim' and password=='123':
        #return redirect('/books')
        response = JsonResponse({'res':1,'msg':'login success!'}) #密码正确,登录成功,返回1

        #如果remember==on,则把用户名,密码设置cookie到cookie
        if remember=='on':
            response.set_cookie('username',username,max_age=7*24*3600)
            #response.set_cookie('password',password,max_age=7*24*3600)
            # 记住用户登录状态把用户名设置到session
            request.session['username'] = username
            # 返回应答
            # 如果用户勾选了remember的条件下,设置session,记住用户登录状态
            request.session['islogin'] = True # 只有session中有islogin,就认为用户已登录
        return response #不要忘记返回response
    else:
        #return redirect('/login')
        return JsonResponse({'res':0,'msg':'login faild'}) #密码错误返回0

6)效果:http://127.0.0.1:8000/login/

Here Insert Picture Description

  1. 用户名、密码、验证码、都正确返回:1 --登录成功
  2. 有一个错误返回 :0-- 登录失败

三、反向解析

  1. 当某一个url配置的地址发生变化时,页面上使用反向解析生成地址的位置不需要发生变化。
  2. 根据url 正则表达式的配置动态的生成url。
  3. 在项目urls中包含具体应用的urls文件时指定namespace;

1)project2/urls.py配置namespace【重点1】

1-1)Django2.0之后写法

【参考】https://blog.csdn.net/weixin_43883625/article/details/100545439
【1】配置namespace,注意写法:re_path(r'^',include(('app2.urls','booktest'),namespace="booktest"))

from django.contrib import admin
from django.urls import path,include,re_path

urlpatterns = [
    path('admin/', admin.site.urls),
    # 【1】配置namespace,注意写法:include(('app2.urls','booktest'),namespace="booktest")
    re_path(r'^',include(('app2.urls','booktest'),namespace="booktest")),
]

1-2)Django2.0之前写法:project2/urls.py配置namespace

【1】2.0之前写法:url(r'^', include('app2.urls', namespace='booktest')),

"""
from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    #【1】2.0之前写法:include('app2.urls', namespace='booktest')
    url(r'^', include('app2.urls', namespace='booktest')),
]

2)app2/urls.py配置 【重点2】

【1】 配置name反向解析配置path('index2/', views.index, name='index')

from django.contrib import admin
from django.urls import path,re_path
from . import views

urlpatterns = [
    # 【1】 配置name反向解析配置path('index2/', views.index, name='index')
    path('index/', views.index, name='index'),
    path('url_reverse/', views.url_reverse),
]

3)app2/views.py写url_reverse函数

# /url_reverse
def url_reverse (request):
    return render(request,'app2/url_reverse.html')

4)模板引用templates/app2/url_reverse.html【重点3】

【1】反向解析模板写法 <a href="{% url 'booktest:index' %}">反向解析</a>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>反向解析</title>
</head>
<body>

<a href="/index">写死地址</a>
<br/>

<!--【1】反向解析模板写法-->
<a href="{% url 'booktest:index' %}">反向解析</a>

</body>
</html>

5)效果:http://127.0.0.1:8000/url_reverse/

写死地址 http://127.0.0.1:8000/index
反向解析 http://127.0.0.1:8000/index

  1. 当2步的path('index/', views.index, name='index')path('index2/', views.index, name='index')时。
  2. 写死地址的连接不会变,反向解析会自动变为:http://127.0.0.1:8000/index2

3.2 反向解析+动态传参

1)app2/views.py

from django.shortcuts import render,redirect
from django.http import HttpResponse,JsonResponse

# show_args
def show_args(request, a, b):
    return HttpResponse(a+':'+b)

# show_kwargs
def show_kwargs(request, c, d):
    return HttpResponse(c+':'+d)

2)【重点1:反向解析+传参配置url】app2/urls.py

【1】反向解析+分组传参数
【2】反向解析+字典传参数(以下两种写法都可)

from django.contrib import admin
from django.urls import path,re_path
from . import views

urlpatterns = [
    re_path(r'^show_args/(\d+)/(\d+)', views.show_args,name='show_args'),#【1】反向解析+分组传参数

    #【2】反向解析+字典传参数(以下两种写法都可)
    #path(r'show_kwargs/<str:c>/<str:d>',views.show_kwargs,name='show_kwargs'),
    path(r'show_kwargs/<c>/<d>',views.show_kwargs,name='show_kwargs'),
  ]

3) [Key 2: Reverse analytical parameter passing + + template wording] templates / app2 / url_reverse.html

[1] + Analytical reverse packet transfer parameters: href="{% url 'booktest:show_args' 1 2 %}"
[2] + dictionary reverse resolution transmission parameters:href="{% url 'booktest:show_kwargs' c=3 d=4 %}"

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>反向解析</title>
</head>
<body>

<a href="/index">写死地址</a>
<br/>
<a href="{% url 'booktest:index' %}">反向解析</a>
<hr/>

<br/>
<a href="/show_args/1/2">写死+分组传参:/show_args/1/2</a><br/>

<br/>
<a href="{% url 'booktest:show_args' 1 2 %}">【1】反向解析+分组传参:/show_args/1/2</a><br/>
{% url 'booktest:show_args' 1 2 %}
<hr/>

<br/>
<a href="/show_kwargs/3/4">写死+字典传参:/show_kwargs/3/4</a><br/>
<br/>

<a href="{% url 'booktest:show_kwargs' c=3 d=4 %}">【2】反向解析+字典传参:/show_kwargs/3/4</a><br/>
{% url 'booktest:show_kwargs' c=3 d=4 %}
</body>
</html>

4) the effect of: http: //127.0.0.1: 8000 / url_reverse /

[1] hardcoded + packet transfer parameters: / show_args / 1/2
[2] reverse lookup + packet transfer parameters: / show_args / 1/2
[3] hardcoded dictionary parameter passing +: / show_kwargs / 3/4
[ 4] reverse resolution mass + dictionary reference: / show_kwargs / 3/4

  • When the 2) step] becomes [[show_args show_args2], [2] [4] can be correctly updated link [1] [2] No
urlpatterns = [
    re_path(r'^show_args2/(\d+)/(\d+)', views.show_args,name='show_args'),#【1】反向解析+分组传参数

    #【2】反向解析+字典传参数(以下两种写法都可)
    #path(r'show_kwargs/<str:c>/<str:d>',views.show_kwargs,name='show_kwargs'),
    path(r'show_kwargs2/<c>/<d>',views.show_kwargs,name='show_kwargs'),
  ]

3.3 views function in reverse resolution calls pass parameters +

1) app2 / views.py focus [1]

  1. redirect('/index')
  2. reverse('booktest:index')
  3. reverse('booktest:show_args', args=(1,2))
  4. reverse('booktest:show_kwargs', kwargs={'c':3, 'd':4})
  5. Remember to return
# from django.core.urlresolvers import reverse #【0-1】2.0之前导入reverse
from django.urls import reverse #【0-2】2.0之后导入reverse

# /test_redirect
def test_redirect(request):
    # 【0写死】重定向到/index
    # return redirect('/index')
    
    # 【1反向解析】
    # url = reverse('booktest:index')

    # 【2反向解析-分组传参】重定向到/show_args/1/2
    url = reverse('booktest:show_args', args=(1,2))

    # 【3反向解析-字典(关键字)传参】重定向到/show_kwargs/3/4
    #url = reverse('booktest:show_kwargs', kwargs={'c':3, 'd':4})
    return redirect(url)

2)app2/urls.py

path('test_redirect/',views.test_redirect),

3) Other configurations see 3.2 (Key 2)

Effect: the 1) step [0-3] multiple-choice 1 comment View lifting effect

Visit: http: //127.0.0.1: 8000 / test_redirect dynamically reverse lookup to the corresponding URL. There is no way to switch 3.2

Guess you like

Origin www.cnblogs.com/chenxi188/p/12186537.html