这一次要搞定的是用户登录,注册和修改密码的功能。一个一个来看吧。
登录功能
原来的系统里使用的是直接在registration目录下创建模板供Django内置的auth模块使用,但是自定义不方便,这一次就自己调用低级的auth功能,来直接创建自己的app,更方便定制页面
创建identity应用
python manage.py startapp identity
然后将其添加到settings.py中,模板目录中也创建同名目录。不在赘述。
用户登录
用户登录需要调用auth模块中的功能,页面则使用JIDOX已经编写好的auth-login.html改造一下。
登录页面
登录页面中前边大段的是背景蓝色渐变的部分,实际的表单从第二个最外层的div标签开始。依次修改图标链接。这里编写了一个单独的message_p.html,可以将消息显示为p标签,然后通过include标签引入即可:
{% if messages %}
{% for message in messages %}
{% if message.level == DEFAULT_MESSAGE_LEVELS.ERROR %}
<p class="text-danger">
{{ message }}
</p>
{% endif %}
{% if message.level == DEFAULT_MESSAGE_LEVELS.INFO %}
<p class="text-info">
{{ message }}
</p>
{% endif %}
{% if message.level == DEFAULT_MESSAGE_LEVELS.SUCCESS %}
<p class="text-success">
{{ message }}
</p>
{% endif %}
{% if message.level == DEFAULT_MESSAGE_LEVELS.WARING %}
<p class="text-warning">
{{ message }}
</p>
{% endif %}
{% endfor %}
{% endif %}
视图函数
配置各种url,最后登录函数对应的url是identity/login/:
from django.contrib import messages
from django.contrib import auth
from django.contrib.auth.models import User
from django.shortcuts import render, redirect
from django.urls import reverse
LOGIN_CUSTOM_URL = 'identity/login/'
def login(request):
if request.method == 'GET':
return render(request, 'identity/login.html')
else:
username = request.POST.get('username')
password = request.POST.get('password')
# 用户不存在进行提示
if not User.objects.filter(username=username).exists():
messages.error(request,f'用户名 {username} 不存在')
path = request.GET.get("next") or reverse('identity:identity_login')
return redirect(path)
# 调用内置验证方法进行验证
user = auth.authenticate(username=username, password=password)
# 成功则跳转next或者首页
if user is not None:
path = request.GET.get("next") or reverse('portal:system_portal')
auth.login(request, user)
return redirect(path)
# 不成功则跳转原来的再次跳转回来
else:
path = request.GET.get("next") or reverse('identity:identity_login')
messages.error(request,f'用户名或密码错误')
return redirect(path)
这里首先定义了一个常量LOGIN_CUSTOM_URL,是为了将来跳转之后能统一跳转到这个路径。
之后就是获取用户名和密码,如果用户名不存在会提示,然后进行验证。成功的话使用auth.login把用户放到session,完成登录,之后就可以通过检查request.user来看是否验证成功了。
用户注册
用户注册的页面也直接拿现成的修改,原模板只提供了一个密码输入框,这里给修改成两个,分别叫password0和passsword1。模板就省略了,和上边一样添加上显示错误信息的功能。
视图编写
主要就是加上两个参数是否相等的判断,然后使用内置的User类直接创建新对象即可。
def register(request):
if request.method == 'GET':
return render(request, 'identity/register.html')
else:
username = request.POST.get('username')
password0 = request.POST.get('password0')
password1 = request.POST.get('password1')
email = request.POST.get('email')
if User.objects.filter(username=username).exists():
messages.error(request, f'用户 {username} 已存在')
return render(request, 'identity/register.html')
if User.objects.filter(email=email).exists():
messages.error(request, f'邮件地址:{email} 已被使用')
return render(request, 'identity/register.html')
if password0 == password1:
User.objects.create_user(username=username, password=password0, email=email, is_active=False).save()
messages.success(request, '注册成功,请联系管理员激活账号后登录')
return redirect(reverse('identity:identity_login'))
else:
messages.error(request, f'输入的密码不一致')
return render(request, 'identity/register.html')
这里默认新用户注册后处于未激活状态,需要管理员手动进行激活。这样可以保证管理员将来还可以给予权限后再激活。
用户登出功能
登出功能在导航条自带的用户菜单里有一个登出选项,就针对这个来搞一下。
页面编写
这里加一个模态框,用于让用户确认登出。
然后修改了判断用户是否登录,来决定显示的菜单内容,还调整了登录与否显示的图标不同。
页面用户部分调整如下:
<li class="dropdown me-md-2">
<a class="nav-link dropdown-toggle arrow-none nav-user px-2" data-bs-toggle="dropdown" href="#"
role="button" aria-haspopup="false" aria-expanded="false">
{% if request.user.is_authenticated %}
<span class="account-user-avatar">
<span class="account-user-avatar fs-24">
<i class="ri-user-follow-fill text-success"></i>
</span>
</span>
{% else %}
<span class="account-user-avatar">
<span class="account-user-avatar fs-24">
<i class="ri-user-unfollow-fill"></i>
</span>
</span>
{% endif %}
<span class="d-lg-flex flex-column gap-1 d-none">
{% if request.user.is_authenticated %}
<span class="my-0">{{ request.user.username }}</span>
<span class="my-0 fw-normal">已登录</span>
{% else %}
<span class="my-0">未登录</span>
{% endif %}
</span>
</a>
<div class="dropdown-menu dropdown-menu-end dropdown-menu-animated profile-dropdown">
{% if request.user.is_authenticated %}
<div class=" dropdown-header noti-title">
<h6 class="text-overflow m-0">Welcome !</h6>
</div>
<a href="#" class="dropdown-item">
<i class="ri-edit-fill align-middle me-1"></i>
<span>修改密码</span>
</a>
<a href="mailto:liyim@shec.com.cn" class="dropdown-item">
<i class="ri-mail-fill align-middle me-1"></i>
<span>联系开发者</span>
</a>
<a href="" class="dropdown-item" data-bs-toggle="modal" data-bs-target="#logout-modal">
<i class="ri-logout-box-fill align-middle me-1"></i>
<span>退出登录</span>
</a>
{% else %}
<a href="{% url 'identity:identity_login' %}?next=/" class="dropdown-item">
<i class="ri-login-box-fill align-middle me-1"></i>
<span>登录</span>
</a>
<a href="mailto:liyim@shec.com.cn" class="dropdown-item">
<i class="ri-mail-fill align-middle me-1"></i>
<span>联系开发者</span>
</a>
{% endif %}
</div>
</li>
登出函数
与官方的不同, 我自己编写的用任意请求都可以退出登录:
@login_required(login_url=LOGIN_CUSTOM_URL)
def logout(request):
auth.logout(request)
return redirect(reverse('portal:system_portal'))
这样就实现了登出功能。
修改密码
修改密码的页面其实就可以拿之前的注册页面进行简单修改,由于用户已经是在登录状态才能访问,所以拿到密码之后先进行检查,检查无误之后再进行修改。页面就不放了,很简单。
视图函数
@login_required(login_url=LOGIN_CUSTOM_URL)
def password_edit(request):
if request.method == 'GET':
return render(request,'identity/password_change.html')
else:
password = request.POST.get('password')
password0 = request.POST.get('password0')
password1 = request.POST.get('password1')
user = request.user
if not user.is_authenticated:
messages.error(request,'当前用户未登录')
return redirect(reverse('identity:identity_login'))
if not User.objects.get(username=user.username).check_password(password):
messages.error(request,'旧密码错误')
return render(request, 'identity/password_change.html')
if password0 != password1:
messages.error(request,'新密码不一致')
return render(request, 'identity/password_change.html')
else:
current_user = User.objects.get(username=user.username)
current_user.set_password(password0)
current_user.save()
auth.logout(request)
messages.success(request,'密码已经修改,请重新登录')
return redirect(reverse('identity:identity_login'))
还有一个密码重置功能,这个就不放出来了,编写一个提示页面,让其找管理员重置密码即可。因为公司的Exchange邮件尚未找到可以直接操作的方法。