一、csrf攻击

1.1 csrf攻击(跨站请求伪造)

【csrf攻击即】:通过第3方网站,伪造请求(前提条件是你已经登录正常网站,并保存了session或cookie登录信息且没有退出),第三方网站即可通过你的session或cookie直接修改正常网站的用户名密码。

  1. 首先做一个登录页,让用户输入用户名和密码进行登录,登录成功之后跳转的修改密码页面。在修改密码页面输入新密码,点击确认按钮完成密码修改。
  2. 登录页需要一个模板文件login.html.修改密码页面也需要一个模板文件change_pwd.html.
  3. 显示登录页的视图login,验证登录的视图login_check,显示发帖页的视图change_pwd,处理修改密码的视图change_pwd_action.
  4. 加功能:

    a)只有用户登录之后才可以进行修改密码操作。
  5. 登录装饰器函数(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. 登录装饰器调用,比如一个页面必须要登录才能操作,否则跳转到登录页

    【app2/views.py】@login_required
# /change_pwd
@login_required #作用:把此页面作为一个参数传到login_required里
def change_pwd(request):
'''显示修改密码页面'''
return render(request, 'booktest/change_pwd.html')

【csrf攻击改密码实例】(必须登录后才能操作):

1) project2/settings.py 注释掉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【登录装饰器】

【1】登录装饰器:用户已登录,调用对应的视图;用户未登录,跳转到登录页

【2】需要登录才能操作的页面调用登录装饰器

【3】需要登录才能操作的页面调用登录装饰器

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登录技术)

<!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)效果:http://127.0.0.1:8000/login/

用户名或密码错误:

不登录直接访问修改密码页面:http://127.0.0.1:8000/change_pwd 跳回登录页
u/p正确(jim,123)跳转到:http://127.0.0.1:8000/change_pwd



然后提示:jim修改密码为:456

7)通过第3方网站修改密码具体操作过程如下:

  1. 首先查看访问服务器的局域网IP及公网IP
ipconfig /all
找到:
192.168.1.4 公网直接百度IP,查看即可
  1. 创建服务,以下操作2选1
如果在局域网创建服务:
py manage.py runserver 192.168.1.4:8000 如果在【虚拟机】或【真正服务器】创建服务:
py manage.py runserver 公网IP:8000
  1. 配置settings.py
DEBUG = False #True
ALLOWED_HOSTS = ['*']
  1. 在局域网另一台电脑访问:192.168.1.4:8000/login 即可访问网站,输入(jim,123)登录成功。
  2. 【创建伪造页】在访问电脑自建一个页面如下:

    【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. 打开第5步的页面,点按键即可修改成功对应网站密码:

  2. 跨站伪造post请求修改用户密码成功!
jim修改密码为:789

1.1.1 django防止csrf的方式:

1) 默认打开csrf中间件(project2/settings.py)。

【1】django默认打开csrf防护,它只对post提交有效

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) 表单post提交数据时加上{% csrf_token %}标签

(对应模板本例:change_pwd.html)。

【注意】:需要有post页面提交的页面必须加上{% csrf_token %},否则即使本站页面也会访问失败。

<!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是Ajax页,所以不能用普通写法

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

  1. 在视图中使用 render(而不要使用 render_to_response)
  2. 在ajax中加:
$.ajaxPost({
data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});
  1. 详细代码:【4】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>

再跨站修改(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 防御原理:

  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">
  1. 服务器同时交给浏览器保存一个名字为csrftoken的cookie信息。
  2. 提交表单时,两个值都会发给服务器,服务器进行比对,如果一样,则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

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/

  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)【重点2:反向解析+传参+模板写法】templates/app2/url_reverse.html

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

【2】反向解析+字典传参: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)效果:http://127.0.0.1:8000/url_reverse/

【1】写死+分组传参:/show_args/1/2

【2】反向解析+分组传参:/show_args/1/2

【3】写死+字典传参:/show_kwargs/3/4

【4】反向解析+字典传参:/show_kwargs/3/4

  • 当2)步的【show_args】变【show_args2】时,【2】【4】都可正确更新链接,【1】【2】不行
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函数里调用反向解析+传参

1)app2/views.py【重点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. 记得返回
# 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)其它配置见3.2(重点2)

效果:把1)步的【0-3】多选1解除注释查看效果

访问:http://127.0.0.1:8000/test_redirect 会动态反向解析到对应的网址。3.2切换也没办法

Django(十六)基于模板的登录案例:登录装饰器、csrf攻击方式及防护、ajax的Post 的csrf开启写法、生成验证码、加验证码登录、反向解析+传参的更多相关文章

  1. django反向解析传参

    这两天写代码总是有反向解析传参顺带复习了一下反向解析,以下是简单的反向解析 以下是我最近写的很多的反向解析传参  想要实现点击修改将这些从数据库读取的内容传到另一个页面就要通过id来查询,那么我们就需 ...

  2. django基础 -- 4. 模板语言 过滤器 模板继承 FBV 和CBV 装饰器 组件

    一.语法 两种特殊符号(语法): {{ }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 二.变量 1. 可直接用  {{ 变量名 }} (可调用字符串, 数字 ,列表,字典,对象等) ...

  3. Django ListView DetailView等基于类的视图如何添加装饰器?

    场景: Django开发中,如果我们使用了类视图,如:ListView.DetailView.UpdateView等,这时我们又想要对这个视图添加一个装饰器,来实现某种功能,这时候该怎么处理呢? 环境 ...

  4. python学习之【第十四篇】:Python中的装饰器

    1.什么是装饰器? 器即函数 装饰即修饰,意指为其他函数添加新功能 装饰器定义:本质就是函数,功能是为其他函数添加新功能 2.遵循的原则 装饰器必须遵循以下两个原则: 不修改被装饰函数的源代码(开放封 ...

  5. django之定义统一返回数据格式与GET/POST装饰器

    1. 为了返回给网页前端的格式统一,定义一个通用的插件类,返回统一格式数据 # enconding:utf-8 """ 定义一个插件类, ""&quo ...

  6. 【Unity Shader编程】之十六 基于MatCap实现适于移动平台的“次时代”车漆Shader

    本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接:http://blog.csdn.net/poem_qianmo/article/details/55803629 渲染本文配图使用的 ...

  7. flask第二十六篇——模板【控制语句】【2】

    如果你也在学flask,就请加船长的公众号:自动化测试实战 我们先补充一下for循环的知识,我们之前说过,flask是由Jinja2+sqlAlchemy+werkzeug组成的,我们现在学的控制语句 ...

  8. Vue-admin工作整理(十六):Ajax-axios进行请求封装+拦截器

    典型的工具类封装,增加拦截起来做相应的处理 user.js: import axios from './index' export const getUserInfo = ({ userId }) = ...

  9. 第六十六篇:Vue的watch侦听器

    好家伙,哇吃侦听器 1.watch侦听器 watch侦听器允许开发者监视数据的变化,从而针对数据的变化做特定的操作 1.1.侦听器的基本用法 <body> <div id=" ...

随机推荐

  1. leetcode 0208

    目录 ✅ 108. 将有序数组转换为二叉搜索树 描述 解答 py [tdo rev 0208]py知识:if not x: 和if x is not None:和if not x is None:使用 ...

  2. 为typecho添加分类描述

    typecho 默认主题不显示分类描述,可以调整为显示 按找官方文档(点击查看),获取分类描述的代码为: <?php echo $this->getDescription(); ?> ...

  3. Airless Pump Bottle For The Rise Of Cosmetic Packaging Solutions

    Airless Pump Bottle    are used in the rise of cosmetic packaging solutions. According to the suppli ...

  4. centos 7中添加一个新用户并授权的步骤详解

    1.创建新用户: 创建一个用户名为:zhangbiao adduser zhangbiao 为这个用户初始化密码,linux会判断密码复杂度,不过可以强行忽略: passwd zhangbiao  更 ...

  5. 13 JavaScript Array对象&Boolean对象&Math对象&RegExp对象

    万物皆对象,数组是对象,数组可以存储元素,函数,数组等对象 创建数组的三个方式: 常规方式:var myCars = new Array(); 简介方式:var myCars = new Arrray ...

  6. Caffe2 模型与数据集(Models and Datasets)[3]

    Models and Datasets 这一节没什么有用的信息为了保证教程完整性,这里仍然保留这一节. 这一节唯一提到的一点就是: Caffe2的模型文件后缀是:.pb2 结语: 转载请注明出处:ht ...

  7. 记录5-如何在UltraEdit中编译和运行Java

    1点击“高级”,再点击“工具配置” 2点击“插入”,在“菜单项”名称上输入“编译java程序”,在“命令行”里输入“javac %n%e”,在工作目录上填“%p”. 3切换到“输出”项,选择“输出到列 ...

  8. LinkedHashMap的用法

    1:LinkedHashMap的简介 Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序.此实现与 HashMap 的不同之处在于,后者维护着一个运行于所有条目的双重链接列表.此链接列表定义了迭 ...

  9. shell 脚本通过Webhook 发送消息到微信群

    代码如下: #!/bin/sh # Filename: msg.sh # # Usage msg.sh "message text" # # 1. check if missing ...

  10. apply()、call()、bind()

    在JavaScript中,call.apply和bind是Function对象自带的三个方法,这三个方法的主要作用是改变函数中的this指向.apply和call方法.bind方法都是在特定的作用域中 ...