Django-Part5——数据交互

[TOC]

前后端交互

发送请求的方式

  1. 浏览器地址栏直接输入url回车 (GET)
  2. a标签href属性 (GET)
  3. form表单 (GET/POST)
  4. ajax (GET/POST)

Ajax

简介

  • Ajax 最大的优点是异步提交,局部刷新。

  • AJAX 不是新的编程语言,而是一种使用现有标准的新方法。

  • Ajax 在这里只学习jQuery封装之后的版本,而不是原生的。所以在前端页面使用ajax的时候需要确保导入了jQuery。

  • 并不只有jQuery能够实现ajax,其他的框架也可以,原理是一样的。

demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>

<link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<input type="text" id="i1"> + <input type="text" id="i2"> = <input type="text" id="i3">
<p>
<button id="btn">点我</button>
</p>

<script>
$('#btn').click(function () {
$.ajax({
// 1. 指定朝哪个地址发请求
url: "", // 不写就是朝当前页面发
// 2. 请求方式
type: 'post', // 不指定,默认为get,都是小写
// 3. 数据,post和get携带参数都是用data表示
{#data:{'username': 'jason', 'password': 123},#}
data: {
'i1': $('#i1').val(),
'i2': $('#i2').val()
},
// 4. 回调函数,异步回调机制,在接收到数据时自动触发
success: function (args) {
{#alert(args) // 即使返回页面也全都由ajax来接收#}
$("#i3").val(args.i3) // 通过DOM操作动态渲染到第三个input里面
}
})
})
</script>

</body>
</html>
1
2
3
4
5
6
7
def ab_ajax(request):
if request.method == 'POST':
print(request.POST)
i1 = int(request.POST.get('i1'))
i2 = int(request.POST.get('i2'))
return JsonResponse({"i3": i1 + i2}) # 无法用 HttpResponse + json.dumps 代替
return render(request, 'index.html')
  • 针对后端如果是用HttpResponse返回的数据,回调函数不会自动反序列化
    • 解决方式1:在前端JSON.parse()
    • 解决方式2:在ajax里面配置一个参数
  • 如果后端直接用的是JsonResponse返回的数据,回调函数会自动反序列化

编码格式(Content-Type)

前后端传输数据的编码格式:

  1. urlencoded(例如:username=jason&password=123)
  2. formdata
  3. json
  4. ……

在form表单中:

  • 默认的数据编码格式是urlencoded,推荐都写成formdata。
  • django针对符合urlencoded编码格式的数据都解析封装到request.POST中。
  • 编码格式设定为formdata时,普通的键值对还是解析到request.POST中,文件将解析到request.FILES中(文件在urlencoded格式下只会解析文件名)。
  • form表单是没有办法发送json格式数据的。

Ajax:

  • 默认的编码格式也是urlencoded
  • 对符合urlencoded编码格式的数据都解析封装到request.POST中

Ajax发送json

前后端传输数据的时候一定要确保编码格式跟数据真正的格式是一致的。

ajax传输json格式数据注意点:

  1. contentType参数指定成:application/json
  2. 数据是原始的json格式数据
  3. django后端不会封装处理json格式数据,需要自己在request.body获取二进制数据并处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
$('#d1').click(function () {
$.ajax({
url: "",
type: 'post',
data: JSON.stringify({
'username': 'jason',
'age': 25
}),
contentType: 'application/json',
success: function (args) {}
})
})
</script>
  • request.is_ajax():判断当前请求是否是ajax请求,返回布尔值
  • request.body:获取请求体,这里是未经处理的二进制数据
  • 处理json文件:json.loads(request.body)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def ab_ajax(request):
if request.method == 'POST':
print(request.is_ajax()) # 判断当前请求是否是ajax请求
print(request.body) # 获取请求体
json_bytes = request.body

# 1. 手动处理二进制流
json_str = json_bytes.decode('utf-8')
json_dict = json.loads(json_str)

# 2. json.loads如果传入二进制数据则自动解码再反序列化
json_dict = json.loads(json_bytes)

return JsonResponse(json_dict)
return render(request, 'index.html')

Ajax发送文件

  1. ajax发送文件需要借助于js内置对象FormData
  2. 需要指定两个关键性的参数 contentType:false processData:false
  3. django能直接识别formdata对象,并将内部的普通键值对自动解析封装到request.POST中,文件数据自动解析封装到request.FILES中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script>
// 点击按钮朝后端发送普通键值对和文件数据
$('#d4').on('click',function () {
// 1. 需要先利用FormData内置对象
let formDateObj = new FormData();
// 2. 添加普通的键值对
formDateObj.append('username',$('#d1').val());
formDateObj.append('password',$('#d2').val());
// 3. 添加文件对象
formDateObj.append('myfile',$('#d3')[0].files[0])
// 4. 将对象基于ajax发送给后端
$.ajax({
url:'',
type:'post',
data:formDateObj, // 直接将对象放在data后面即可
// ajax发送文件必须要指定的两个参数
contentType:false, // 不需使用任何编码 django后端能够自动识别formdata对象
processData:false, // 告诉你的浏览器不要对你的数据进行任何处理
success:function (args) {}
})
})
</script>
1
2
3
4
5
6
def ab_file(request):
if request.is_ajax():
if request.method == 'POST':
print(request.POST)
print(request.FILES)
return render(request,'ab_file.html')

Django自带的序列化组件

  • 使用django.core.serializers.serialize('指定数据格式', 数据本体)快速完成序列化
  • 后续还有更多的序列化组件,例如:drf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 需求:在前端获取后端用户表里面所有的数据,列表套字典
from django.http import JsonResponse
from django.core import serializers
def ab_ser(request):
user_queryset = models.User.objects.all()
# user_list = []
# for user_obj in user_queryset:
# tmp = {
# 'pk':user_obj.pk,
# 'username':user_obj.username,
# 'age':user_obj.age,
# 'gender':user_obj.get_gender_display()
# }
# user_list.append(tmp)
# return JsonResponse(user_list, safe=False)

# 序列化
res = serializers.serialize('json', user_queryset)
return HttpResponse(res)

Ajax结合SweetAlert

  • 每个元素都可以自定义属性,可以用来传值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<script>
$('.del').on('click', function () {
// 1. 先将当前标签对象存储起来
let currentBtn = $(this);
// 2. 二次确认弹框
swal({
title: "你确定要删吗?",
text: "你可要考虑清除哦,可能需要拎包跑路哦!",
type: "warning",
showCancelButton: true,
confirmButtonClass: "btn-danger",
confirmButtonText: "是的,老子就要删!",
cancelButtonText: "算了,算了!",
closeOnConfirm: false,
closeOnCancel: false,
showLoaderOnConfirm: true
}, function (isConfirm) {
if (isConfirm) {
// 3. 朝后端发送ajax请求删除数据,之后弹完成情况的提示框
$.ajax({
url: '/delete/user/', // 传递主键值可以放在url中,也可以放在请求体里面
type: 'post',
data: {'delete_id': currentBtn.attr('delete_id')},
success: function (args) { // args = {'code': '', 'msg': ''}
// 4. 判断响应状态码,然后做不同的处理
if (args.code === 1000) {
swal("删了!", args.msg, "success");
// (1) lowb版本 直接刷新当前页面
{#window.location.reload()#}
// (2) 利用DOM操作 动态刷新
currentBtn.parent().parent().remove()
} else {
swal('完了', '出现了位置的错误', 'info')
}
}
})
} else {
swal("怂逼", "不要说我认识你", "error");
}
});
})
</script>

forms组件

forms组件能够完成的事情:

  1. 渲染html代码
  2. 校验数据
  3. 展示提示信息

数据校验前端可有可无,但是后端必须要有!

因为前端的校验是弱不禁风的,可以直接修改,或者利用爬虫绕过前端页面直接朝后端提交数据。

定义forms组件

1
2
3
4
5
6
7
8
9
from django import forms

class MyForm(forms.Form):
# username字符串类型最小3位最大8位
username = forms.CharField(min_length=3, max_length=8, label='用户名')
# password字符串类型最小3位最大8位
password = forms.CharField(min_length=3, max_length=8)
# email字段必须符合邮箱格式 xxx@xx.com
email = forms.EmailField()

校验数据

  • 可以直接在 python console 中测试
  • 默认情况下数据可以多传但是绝不可能少传
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from app01 import views
# 1 将带校验的数据组织成字典的形式传入即可
form_obj = views.MyForm({'username':'jason','password':'123','email':'123'})
# 2 判断数据是否合法:注意该方法只有在所有的数据全部合法的情况下才会返回True
form_obj.is_valid() # False
# 3 查看所有校验通过的数据
form_obj.cleaned_data # {'username': 'jason', 'password': '123'}
# 4 查看所有不符合校验规则以及不符合的原因
form_obj.errors # {'email': ['Enter a valid email address.']}
# 5 只校验类中出现的字段,多传的字段直接忽略
form_obj = views.MyForm({'username':'jason','password':'123','email':'123@qq.com','hobby':'study'})
form_obj.is_valid() # True
# 6 默认情况下,类里面所有的字段都必须传值
form_obj = views.MyForm({'username':'jason','password':'123'})
form_obj.is_valid() # False

渲染标签

  • forms组件只会自动渲染获取用户输入的标签(input select radio checkbox),不能渲染提交按钮
  • 设置form表单让浏览器不做校验<form action="" method="post" novalidate>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def index(request):
# 1. 先生成一个空对象
form_obj = MyForm()
if request.method == 'POST':
"""
1. 多个字段的数据获取繁琐
2. 校验数据需要构造成字典的格式传入
3. request.POST就是一个字典
4. 对于提供多余的字段不在意
"""
# 3. 校验数据
form_obj = MyForm(request.POST)
# 4. 判断数据是否合法
if form_obj.is_valid():
# 5. 合法,操作数据库存储数据
return HttpResponse('OK')
# 5. 不合法,有错误。此时可以基于上一次结果进行修改
# 2. 直接将该空对象传递给html页面
return render(request, 'index.html', locals())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  <p>第一种渲染方式:代码书写极少,封装程度太高,不便于后续的扩展,一般情况下只在本地测试使用</p>
{{ form_obj.as_p }}
{{ form_obj.as_ul }}
{{ form_obj.as_table }}

<p>第二种渲染方式:可扩展性很强 但是需要书写的代码太多,一般情况下不用</p>
<p>{{ form_obj.username.label }}:{{ form_obj.username }}</p>
<p>{{ form_obj.password.label }}:{{ form_obj.password }}</p>
<p>{{ form_obj.email.label }}:{{ form_obj.email }}</p>

<p>第三种渲染方式(推荐使用):代码书写简单 并且扩展性也高</p>
{% for form in form_obj %}
<p>
{{ form.label }}:{{ form }}
<span style="color: red">{{ form.errors.0 }}</span>
</p>
{% endfor %}

自定义错误信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class MyForm(forms.Form):
# username字符串类型最小3位最大8位
username = forms.CharField(min_length=3, max_length=8, label='用户名',
error_messages={
'min_length': '用户名最少3位',
'max_length': '用户名最大8位',
'required': "用户名不能为空"
})
# password字符串类型最小3位最大8位
password = forms.CharField(min_length=3, max_length=8, label='密码',
error_messages={
'min_length': '密码最少3位',
'max_length': '密码最大8位',
'required': "密码不能为空"
})
# email字段必须符合邮箱格式 xxx@xx.com
email = forms.EmailField(label='邮箱',
error_messages={
'invalid': '邮箱格式不正确',
'required': "邮箱不能为空"
})

钩子函数(HOOK)

  • 钩子函数将书写在Form类中,能够让我们自定义校验规则
  • 在forms组件中有两类钩子
    1. 局部钩子:给单个字段增加校验规则
    2. 全局钩子:给多个字段增加校验规则
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class MyForm(forms.Form):
......
# 局部钩子
def clean_username(self):
# 获取用户名
username = self.cleaned_data.get('username')
if '666' in username:
# 1. 校验用户名中不能含有666,添加错误信息
self.add_error('username', '光喊666是不行滴~')
# 将钩子函数钩去出来得特定数据放回去
return username

# 全局钩子
def clean(self):
password = self.cleaned_data.get('password')
confirm_password = self.cleaned_data.get('confirm_password')
if not confirm_password == password:
# 2. 校验密码和确认密码是否一致
self.add_error('confirm_password', '两次密码不一致')
# 将钩子函数钩出来的所有数据放回去
return self.cleaned_data

forms字段其他参数与样式渲染

  • label:字段名
  • error_messages:自定义报错信息
  • initial:默认值
  • required:控制字段是否必填
  • widget:type类型
    • attrs:以字典类型定义属性
  • validators:可以使用RegexValidator添加正则表达式校验
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
class MyForm(forms.Form):
username = forms.CharField(min_length=3, max_length=8, label='用户名', initial='jason', required=False,
widget=forms.widgets.TextInput(attrs={'class': 'form-control'}),
error_messages={
'min_length': '用户名最少3位',
'max_length': '用户名最大8位',
'required': "用户名不能为空"
})
password = forms.CharField(min_length=3, max_length=8, label='密码',
widget=forms.widgets.PasswordInput(attrs={'class': 'form-control c1 c2'}),
error_messages={
'min_length': '密码最少3位',
'max_length': '密码最大8位',
'required': "密码不能为空"
})
confirm_password = forms.CharField(min_length=3, max_length=8, label='确认密码',
widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}),
error_messages={
'min_length': '确认密码最少3位',
'max_length': '确认密码最大8位',
'required': "确认密码不能为空"
})
email = forms.EmailField(label='邮箱', widget=forms.widgets.EmailInput(attrs={'class': 'form-control'}),
error_messages={
'invalid': '邮箱格式不正确',
'required': "邮箱不能为空"
})
phone = forms.CharField(validators=[
RegexValidator(r'^[0-9]+$', '请输入数字'),
RegexValidator(r'^159[0-9]+$', '数字必须以159开头')
])

# radio
gender = forms.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性别",
initial=3,
widget=forms.widgets.RadioSelect()
)
# 单选select
hobby = forms.ChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=3,
widget=forms.widgets.Select()
)
# 多选select
hobby1 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()
)
# 单选checkbox
keep = forms.ChoiceField(
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput()
)
# 多选checkbox
hobby2 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
)

choice字段实时更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from django.forms import Form
from django.forms import widgets
from django.forms import fields


class MyForm(Form):
# 方式一
user = fields.ChoiceField(
# choices=((1, '上海'), (2, '北京'),),
initial=2,
widget=widgets.Select
)
def __init__(self, *args, **kwargs):
super(MyForm,self).__init__(*args, **kwargs)
# self.fields['user'].choices = ((1, '上海'), (2, '北京'),)
# 或
self.fields['user'].choices = models.Classes.objects.all().values_list('id', 'caption')

# 方式二
authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all()) # 多选
# authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all()) # 单选

Cookie与Session

目标:

  • 为了保持用户登陆状态。

Cookie:

  • 登陆之后,将用户的信息返回给用户浏览器,保存在本地,之后访问网站的时候携带保存在浏览器上的用户信息发送给服务端,自动验证。
  • 服务端保存在客户端浏览器上的信息都可以称之为cookie。
  • 它的表现形式一般都是k:v键值对(可以有多个)。

Session:

  • 登陆之后,服务端保存kv键值对形式的数据。k为随机字符串,交由客户端浏览器保存,v为用户信息。
  • 数据保存在服务端,并且表现形式一般也是k:v键值对。
  • Session是基于Cookie工作的(包括其他保存用户操作的状态都需要使用到cookie)。

Token:

  • 为了减轻Session给服务端带来的压力:随着连接数增多,服务端保存的数据量越大。
  • 登陆之后,将用户信息进行公司内独有的加密处理,并将多段数据拼接(jwt认证),整体返回给浏览器保存。
  • 浏览器之后访问的时候带着密文,服务端自动解密并比对。

Cookie操作

  • 虽然cookie是服务端要求客户端需要保存内容,但是客户端可以选择拒绝保存,如果禁止,那么只要是需要记录用户状态的网站功能都无法使用了。
  • 如果想要操作cookie,就不得不使用HttpResponse对象。

Cookie方法:

  1. HttpResponseObject.set_cookie(key,value):设置cookie
  2. request.COOKIES.get(key):获取cookie
  3. HttpResponseObject.set_cookie(key, value, max_age, expires):在设置cookie的时候可以添加一个超时时间
    • max_age、expires 都是设置超时时间的,并且都是以秒为单位,针对IE浏览器需要使用expires。
  4. HttpResponseObject.delete_cookie(key):清除Cookie
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 校验用户是否登陆的装饰器
def login_auth(func):
def inner(request, *args, **kwargs):
target_url = request.get_full_path() # 能够获取到用户上一次想要访问的url
if request.COOKIES.get('username'):
return func(request, *args, **kwargs)
return redirect('/login/?next=%s' % target_url)
return inner


def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username == 'jason' and password == '123':
# 获取用户上一次想要访问的url
target_url = request.GET.get('next') # 这个结果可能是None
if target_url:
obj = redirect(target_url)
else:
obj = redirect('/home/')
# 让浏览器记录cookie数据,保存用户登陆状态,超时时间3秒到期
obj.set_cookie('username', 'jason666', max_age=3)
# 跳转到一个需要用户登陆之后才能看的页面
return obj
return render(request, 'login.html')


@login_auth
def home(request):
return HttpResponse("我是home页面,只有登陆的用户才能进来哟~")


@login_auth
def logout(request):
obj = redirect('/login/')
obj.delete_cookie('username')
return obj

对装饰器的详细解释:https://www.runoob.com/w3cnote/python-func-decorators.html

Session操作

  • Session数据是保存在服务端的,给客户端返回的是一个key为sessionid、value为随机字符串的键值对。

  • 在使用Session之前要使用数据库迁移命令,因为Session的数据是存储在django_session表中的。

  • Django默认session的过期时间是14天。

  • django_session表中的数据条数是取决于 user-agent ,同一个浏览器在期限内只会有一条数据被写入在表中。

    当session过期时,可能会出现多条数据对应一个IP地址,但是该现象不会持续很久,内部会自动清除过期的数据,也可以通过代码手动清除。

  • session保存位置可以有多种选择:1. MySQL 2. 文件 3. redis 4. memcache

Session方法:

  1. request.session['key'] = value:设置session
  2. request.session.get('key'):获取session
  3. request.session.set_expiry():设置过期时间
    • 非零正数:持续的秒数
    • datetime或timedelta日期对象:指定日期失效
    • 0:一旦浏览器窗口关闭则失效
    • None:session会依赖全局session失效策略
  4. request.session.delete():清除session,只删服务端的,客户端的不删
  5. request.session.flush():清除session,浏览器和服务端都清空(推荐使用)
  6. request.session.session_key:会话session的key
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def set_session(request):
request.session['hobby'] = 'girl'
request.session.set_expiry(5)
"""
1. django内部自动生成一个随机字符串
2. django内部自动将随机字符串和对应的数据存储到django_session表中
2.1 先在内存中产生操作数据的缓存
2.2 在响应结果经过django中间件时才真正地操作数据库
django.contrib.sessions.middleware.SessionMiddleware
3. 将产生的随机字符串返回给客户端浏览器保存
"""
return HttpResponse('嘿嘿嘿')


def get_session(request):
if request.session.get('hobby'):
print(request.session)
print(request.session.get("hobby"))
"""
1. 先从请求中获取sessionid对应的随机字符串
2. 拿着该随机字符串去django_session表中查找对应的数据
2.1 如果比对上了,则将对应的数据取出并以字典的形式封装到request.session中
2.2 如果比对不上,则request.session.get()返回None
"""
return HttpResponse("哈哈哈")
return HttpResponse("大爷 关门了 明晚再来吧")

利用session实现登陆验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
from functools import wraps


def check_login(func):
@wraps(func)
def inner(request, *args, **kwargs):
next_url = request.get_full_path()
if request.session.get("user"):
return func(request, *args, **kwargs)
else:
return redirect("/login/?next={}".format(next_url))
return inner


def login(request):
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd")
if user == "alex" and pwd == "alex1234":
# 设置session
request.session["user"] = user
# 获取跳到登陆页面之前的URL
next_url = request.GET.get("next")
# 如果有,就跳转回登陆之前的URL
if next_url:
return redirect(next_url)
# 否则默认跳转到index页面
else:
return redirect("/index/")
return render(request, "login.html")


@check_login
def logout(request):
# 删除所有当前请求相关的session
request.session.flush()
return redirect("/login/")


@check_login
def index(request):
current_user = request.session.get("user", None)
return render(request, "index.html", {"user": current_user})

CBV添加装饰器

加在CBV的get或post方法上

1
2
3
4
5
6
7
8
9
10
from django.utils.decorators import method_decorator

class HomeView(View):
def get(self, request):
return render(request, "home.html")

@method_decorator(check_login)
def post(self, request):
print("Home View POST method...")
return redirect("/index/")

加在dispatch方法上

因为CBV中首先执行的就是dispatch方法,所以直接作用于当前类里面的所有的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
from django.utils.decorators import method_decorator

class HomeView(View):
@method_decorator(check_login)
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs)

def get(self, request):
return render(request, "home.html")

def post(self, request):
print("Home View POST method...")
return redirect("/index/")

加在视图类上

如果get方法和post方法都需要登录校验的话就写两个装饰器。

但method_decorator必须传 name 关键字参数

1
2
3
4
5
6
7
8
9
10
11
from django.utils.decorators import method_decorator

@method_decorator(check_login, name="get")
@method_decorator(check_login, name="post")
class HomeView(View):
def get(self, request):
return render(request, "home.html")

def post(self, request):
print("Home View POST method...")
return redirect("/index/")