前言
最近在复习django时发现了装饰器的相关内容,觉得挺有意思的,为此做下记录。
一、装饰器语法
先说明一下装饰器,python的装饰器类似于java的注解,可以用在方法上面。按我的理解,被装饰器装饰的方法,其实是先执行装饰器里面的代码,然后再执行方法里面的代码。语法如下:
def 装饰器名字(传入方法名):
# 这个函数名字随便起,下面返回的函数名要和这个函数名一致
def 执行函数名(传入方法的参数列表):
# 你想做的操作
........
# 返回传入方法
return 传入方法名(传入方法的参数列表)
# 返回执行函数
return 执行函数
二、装饰器解释
下面举个例子,decorator_count是我自定义的一个装饰器
def decorator_count(func):
def dec_count(i, j):
print("装饰器代码已执行")
return func(i, j)
return dec_count
@decorator_count
def count(i, j):
print(i+j)
if __name__ == '__main__':
count(1, 2)
以上程序的执行结果是:
装饰器代码已执行
3
为什么结果是这样,其实count()方法给装饰器装饰之后,装饰器里面的代码和下面代码类似:
# 这里参数变了
def decorator_count(count):
def dec_count(i, j):
print("装饰器代码已执行")
# 这里也变了
return count(i, j)
return dec_count
这就不难看出,装饰器返回了dec_count()方法,而在dec_count()方法里面,又先执行了print(),再执行count(i, j),所以才会有上面的输出顺序。
三、装饰器实现访问和权限控制
页面的访问是先判断用户是否登录,再返回页面,和上面的先执行print(),再执行count(i, j)是不是很像,那使用装饰器判断用户是否登录就很简单了
1、准备
先准备好有关的模型类,视图和页面,以你的实际项目为准,这里只给出有关的视图方法
自定义装饰器“decorator_logined.py”,判断用户是否已经登录(我这里根据session中是否存在用户名来判断用户是否登录)
from django.shortcuts import redirect
# 装饰器名字
def already_login(func):
# 这个函数名字随便起,下面返回的函数名要和这个函数名一致
# 参数列表参考要传入函数
def alr_login(request, *args, **kwargs):
un = request.session.get("username")
# 判断是否已经登录了
if un:
return func(request, *args, **kwargs)
else:
# 没登录的先登录
return redirect('/before_index/')
return alr_login
自定义装饰器“decorator_permission.py”,判断用户是否有权限操作(我这里根据group_id判断用户权限)
from django.http import HttpResponse
def validate_permission(func):
def valid_per(request, *args, **kwargs):
# 获取用户所在的用户组id
group_id = request.session.get('group_id')
# 判断是否有对应访问权限了
if group_id == 0:
return func(request, *args, **kwargs)
else:
return HttpResponse("你无权访问!")
return valid_per
在视图中使用()装饰器用在首页和用户列表:
from django.shortcuts import render, redirect
from .forms import UserForm
from .models import User
from Decorator.decorator_permission import validate_permission
from Decorator.decorator_logined import already_login
# Create your views here.
# 登录
def login(request):
if request.method == "GET":
return render(request, "login/login.html")
if request.method == "POST":
# 获取数据
obj = UserForm(request.POST)
# 校验数据
if obj.is_valid():
# 获取obj里面的数据
user = User.objects.values("id", "username", "group_id").filter(**obj.cleaned_data).first()
# 在数据库中能找到对应用户
if user:
# 将相关信息保存到session中并返回
request.session['id'] = user['id']
request.session['username'] = user["username"]
request.session['group_id'] = user["group_id"]
# 重定向到首页
return redirect('/index/')
else:
errmsg = {'errmsg': "用户名或者密码错误"}
return render(request, 'login/login.html', errmsg)
content = {"obj": obj}
return render(request, 'login/login.html', content)
# 首页
@already_login
def index(request):
# 获取用户名已经对应的用户组id
username = request.session.get("username")
group_id = request.session.get("group_id")
content = {"username": username, "group_id": group_id}
return render(request, 'login/index.html', content)
# 查看用户列表
@already_login
@validate_permission
def userList(request):
userList = User.objects.all()
content = {"userList": userList}
return render(request, "user/user_list.html", content)
# 没登录用户进入首页时的跳转界面
def before_index(request):
return render(request, "login/before_index.html")
注意:使用多个装饰器装饰同一个方法时装饰器是由上往下依次执行
2、测试
我的用户列表如下,只有group_id为0的用户能访问用户列表:
没登录时输入首页地址:
登录之后输入用户列表地址:
登录管理员账号输入用户列表地址:
大功告成!!!想要判断用户是否登录和用户操作权限,只需要引入对应的装饰器就可以啦。
有什么问题欢迎在评论区留言。
四、附上web页面代码
1、目录结构
2、代码
1.before_index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>请先登录</title>
</head>
<body>
<h1>请先登录再操作</h1>
<a href="/login/">跳转到登录界面</a>
</body>
</html>
2.index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>首页</h1>
<div>欢迎: {{ username }}</div>
<a href="/login_out/">登出</a>
{% if group_id == 0 %}
<a href="/userlist/">用户列表</a>
{% endif %}
</body>
</html>
3.login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<div>
<h2>登录界面</h2>
<form action="." method="post">
{% csrf_token %}
{{ errmsg }}
用户名: <input name="username">{{ obj.username.errors.0 }}<br>
密码: <input name="password">{{ obj.password.errors.0 }}<br>
<button type="submit">登录</button>
<a href="/register/">注册</a>
</form>
</div>
</body>
</html>
4.user_list.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户列表</title>
</head>
<body>
<h1>用户列表</h1>
{% for user in userList %}
<li>{{ user.username }}</li>
{% endfor %}
</body>
</html>