FMS 2026 开发记录 02

FMS 2026 开发记录 02

这次来编写最基础的用户管理功能。和基础应用结合在一起

这一次要搞定的是用户登录,注册和修改密码的功能。一个一个来看吧。

登录功能

原来的系统里使用的是直接在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,最后登录函数对应的urlidentity/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来看是否验证成功了。

用户注册

用户注册的页面也直接拿现成的修改,原模板只提供了一个密码输入框,这里给修改成两个,分别叫password0passsword1。模板就省略了,和上边一样添加上显示错误信息的功能。

视图编写

主要就是加上两个参数是否相等的判断,然后使用内置的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邮件尚未找到可以直接操作的方法。

LICENSED UNDER CC BY-NC-SA 4.0
Comment