从零开始的Django框架入门到实战教程(内含实战实例) - 06 管理员界面 密码加密保存、密码不显示、密码重置、密码确认、密码校验 详解(学习笔记)

11 篇文章 46 订阅


  Django是目前比较火爆的框架,之前有在知乎刷到,很多毕业生进入大厂实习后因为不会git和Django框架3天就被踢掉了,因为他们很难把自己的工作融入到整个组的工作中。因此,我尝试自学Django并整理出如下笔记。
  这篇博客主要完善了之前的一些功能,代码适合更多的引用场景。包括管理员的密码加密(md5),管理员密码不显示(forms.PasswordInput),管理员密码重置(save()),管理员密码确认(ValidationError),管理员密码修改时校验(ValidationError)。实际上,就是在之前的增删改查的大框架下根据不同的应用场景修改一些边边角角的地方。部分工作基于原来已有的工作。

1. 介绍

  因为这个小任务已经进行了很多工作了,有之前任务的积累。如果直接看代码可能会被文件之间的关系整迷糊,这里梳理一下关键的文件和文件夹的内容。
在这里插入图片描述

static							包含各种静态文件,css样式,jquery等
templates						包含各种html文件,所有的静态页面都是这里出来的
utils							包含各种中途会用到的工具
	- bootstrap_input.py		继承ModelForm,在其中嵌入Bootstrap样式
	- encrypt.py				利用md5加密密码
	- form.py					所有的ModelForm存这里
	- page.py					分页类,负责为界面添加分页功能
views
	- admin.py					管理员界面的views放这里
	- depart.py					部门界面的views放这里
	- num.py					号码界面的views放这里
	- user.py					用户界面的views放这里
__init__.py						略
admin.py						略
apps.py							略
models.py						存放我们对数据库的数据表的定义
test.py 						略
Employee_Management
	- __init__.py				略
	- asgi.py					略
	- settings.py				略
	- urls.py					views内的py文件中各个函数与templates内html文件的对应关系
	- wsgi.py					略

2. 管理员界面

  制作界面之前,我们首先要完成数据表的建立。还是要在models.py中创建管理员类,并通过命令行在终端中链接数据库。

# 管理员
class Admin(models.Model):
    username = models.CharField(verbose_name="用户名", max_length=32)
    password = models.CharField(verbose_name="密码", max_length=64)

  除了数据库本身,我们还需要把界面展示到前端。这需要我们连接数据库,将数据传入到前端;完成前端界面的设计;加入前端的框架。

  使用ModelForm连接数据库。utils/form.py

from django import forms
# 加入Bootstrap样式
class BootstrapModelForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            field.widget.attrs["class"] = "form-control"
            field.widget.attrs["placeholder"] = field.label

# ModelForm
class AdminModelForm(BootstrapModelForm):
    class Meta:
        model = models.Admin
        # confirm_password在输入密码时用于确认密码
        fields = ["username", "password"]
        widgets = {
            "password": forms.PasswordInput
        }

  连接数据库,使用将所有的数据传到前端。其中,PAGE是我们之前自己封装的一个类,可以根据结果分页(04 号码管理部分() 1.7. 分页(封装类实现))

from django.shortcuts import render, redirect
from application01 import models
from application01.utils.page import PAGE
from application01.utils.form import AdminModelForm
def admin_list(request):
    # 搜索功能
    search_dict = dict()
    value = request.GET.get("search", "")
    if value:
        search_dict["username__contains"] = value

    # 如果有搜索就会读取搜索之后的结果。所有的结果都会根据id排序
    admin_list = models.Admin.objects.filter(**search_dict).order_by("id")
    # 分页
    page_object = PAGE(request, admin_list, page_size=8)
    context = {
        "admin_list": page_object.page_queryset,  # 分完页的数据
        "search_data": value,  # 搜索之后的数据
        "page_string": page_object.create_html(),  # 生成的页码
        "search_page": page_object.search()  # 搜索功能
    }

    # 传送到前端
    return render(request, "admin_list.html", context)

  admin_list.html(看不懂首行的layout.html可以看03 前端模板嵌套3. 模板的继承):

{% extends "layout.html" %}
{% block content %}
<div class="container">
    <div style="margin-bottom: 10px">
        <a class="btn btn-success" href="/admin/add">
            <span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
            加入管理员
        </a>
        <div style="float: right; width: 300px;">
            <form method="get">
                <div class="input-group">
                    <input type="text" class="form-control" placeholder="搜索用户名" name="search" value="{{search_data}}">
                    <span class="input-group-btn">
                        <button class="btn btn-default" type="submit">
                            <span class="glyphicon glyphicon-search"></span>
                        </button>
                    </span>
                </div>
            </form>
        </div>
    </div>

    <div class="panel panel-default">
        <!-- Default panel contents -->
        <div class="panel-heading">
            <span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
            管理员列表
        </div>
        <!-- Table -->
        <table class="table table-bordered">
            <thead>
            <tr>
                <th>ID</th>
                <th>用户名</th>
                <th>密码</th>
                <th>操作</th>
            </tr>
            </thead>
            <tbody>
            {% for obj in admin_list %}
            <tr>
                <th>{{ obj.id }}</th>
                <td>{{ obj.username }}</td>
                <td>********</td>
                <td>
                    <a class="btn btn-primary btn-xs" href="/admin/{{ obj.id }}/edit">编辑</a>
                    <a class="btn btn-danger btn-xs" href="/admin/{{ obj.id }}/del">删除</a>
                </td>
            </tr>
            {% endfor %}
            </tbody>
        </table>
    </div>
    <ul class="pagination" style="width:100%;">
        {{ page_string }}
        {{ search_page }}
    </ul>
</div>
{% endblock %}

  效果如下:

在这里插入图片描述

3. 添加管理员

  添加管理员类似的任务我们在之前有做过很多:添加用户、添加号码、添加部门……这次我们做出一些改变。我们在上网的时候应该都有过类似的体验:我们在注册账号时,平台为了防止我们输错密码,会加入一个“请再次输入密码”,我们也完成这个功能。此外,为了防止信息泄露,我们还要给管理员的密码加入加密功能。

  首先是在utils/form.py中修改ModelForm:

from application01.utils.encrypt import md5
from application01.utils.bootstrap_input import BootstrapModelForm
from django import forms
from django.core.validators import RegexValidator, ValidationError

class AdminModelForm(BootstrapModelForm):
    # 定义“确认密码”
    confirm_password = forms.CharField(
        label="确认密码",
        widget=forms.PasswordInput(render_value=True)       # 密码不一致之后,报错之后不置空
    )

    class Meta:
        model = models.Admin
        # confirm_password在输入密码时用于确认密码
        fields = ["username", "password", "confirm_password"]
        widgets = {
            "password": forms.PasswordInput
        }
    
    # 确定是否存在此管理员
    def clean_username(self):
        text_admin = self.cleaned_data["username"]
        exists = models.Admin.objects.filter(username=text_admin).exists()
        if exists:
            raise ValidationError("管理员已存在")
        return text_admin
	
    # 加密
    def clean_password(self):
        pwd = self.cleaned_data.get("password")
        return md5(pwd)

    # 对比两次输入的密码
    def clean_confirm_password(self):
        pwd = self.cleaned_data.get("password")
        confirm = md5(self.cleaned_data.get("confirm_password"))
        if pwd != confirm:
            raise ValidationError("密码不一致,请重新输入")
        return confirm

  其中,md5加密函数位于utils/encrypt.py中。

# -*- coding:utf-8 -*-
from django.conf import settings
import hashlib

# 加密
def md5(data):
    # SECRET_KEY是Django自带的
    obj = hashlib.md5(settings.SECRET_KEY.encode("utf-8"))
    obj.update(data.encode("utf-8"))
    return obj.hexdigest()

  views/admin.py

def admin_add(request):
    # 如果没有信息POST过来,我们通过如下代码生成界面,等待POST
    if request.method == "GET":
        form = AdminModelForm()
        return render(request, "admin_add.html", {"form": form})
    form = AdminModelForm(data=request.POST)
    # 有数据POST过来之后
    # 如果数据通过了校验,保存数据
    if form.is_valid():
        form.save()
        return redirect("/admin/list")
    # 如果数据没有通过校验,还是在添加界面,同时返回错误
    return render(request, "admin_add.html", {"title": "新建管理员", "form": form})

   admin_add.html

{% extends 'layout.html' %}

{% block content %}
<div class="container">
    <div class="panel panel-default">
        <div class="panel-heading">
            <h3 class="panel-title">{{ title }}</h3>
        </div>
        <div class="panel-body">
            <form method="post" novalidate>
                {% csrf_token %}
                {% for field in form %}
                <div class="form-group">
                    <label>{{ field.label }}</label>
                    {{ field }}
                    <span style="color:red;">{{ field.errors.0 }}</span>
                </div>
                {% endfor %}
                <button type="submit" class="btn btn-primary">提 交</button>
            </form>
        </div>
    </div>
</div>
{% endblock %}

  效果如下:

在这里插入图片描述

4. 管理员编辑

  编辑部分大同小异,不过我们加入了权限。后台无法修改管理员的用户名,此外,后台也无法通过平台得到管理员的密码的明文,只有重置密码的权力(6. 管理员密码重置)。为了提高系统的稳定性,我们再加入判断,防止用户输入不存在的管理员编号。

  我们特地为编辑写一个ModelForm,因为我们不希望修改后的密码跟之前的密码一样,所以修改之前的clean_password,在里面加了一个校验。utils/forms.py

class AdminEditModelForm(BootstrapModelForm):
    confirm_password = forms.CharField(
        label="确认密码",
        widget=forms.PasswordInput(render_value=True)  # 密码不一致之后,报错之后不置空
    )
    username = forms.CharField(disabled=True, label="用户名")
    class Meta:
        model = models.Admin
        fields = ["username", "password", "confirm_password"]

    def clean_password(self):
        pwd = self.cleaned_data.get("password")
        md5_pwd = md5(pwd)
        # 校验当前密码和新输入的密码是否一致
        # instance 就是传进来的对象,pk就是id
        exist = models.Admin.objects.filter(id=self.instance.pk, password=md5_pwd).exists()
        if exist:
            raise ValidationError('密码不能与之前的密码相同')
        return md5_pwd

    def clean_confirm_password(self):
        pwd = self.cleaned_data.get("password")
        confirm = md5(self.cleaned_data.get("confirm_password"))
        if pwd != confirm:
            raise ValidationError("密码不一致,请重新输入")
        return confirm

  当然,如果你不想让用户看到明文,也可以直接给password一个widget=forms.PasswordInput(render_value=True)

  连接数据库。views/admin.py

def admin_edit(request, nid):
    # 判断nid存不存在
    row_obj = models.Admin.objects.filter(id=nid).first()
    if not row_obj:
        return render(request, 'error.html', {'msg': '数据不存在'})
    # 显示默认值
    if request.method == 'GET':
        form = AdminEditModelForm(instance=row_obj)
        return render(request, "admin_add.html", {"title": "编辑管理员", "form": form})
    form = AdminEditModelForm(instance=row_obj, data=request.POST)
    # 校验
    if form.is_valid():
        form.save()
        return redirect("/admin/list")
    return render(request, "admin_add.html", {"title": "编辑管理员", "form": form})

  效果如下:
在这里插入图片描述

5. 删除管理员

  这部分毫无改变,其实也没啥能改的。

def admin_del(request, nid):
    models.Admin.objects.filter(id=nid).delete()
    return redirect('/admin/list')

在这里插入图片描述

6. 管理员密码重置

  在现实情况中,很多情况下,即使是后台人员也不可以直接查看用户的隐私,这个时候如果用户忘记了密码,我们就没有办法直接去改它,我们往往会选择直接重置这个密码。在用户重置密码之后,将跳出提醒界面,并将密码重置为1129。

def admin_reset(request, nid):
    row_obj = models.Admin.objects.filter(id=nid).first()
    if not row_obj:
        return render(request, 'error.html', {'msg': '数据不存在'})
    # 显示默认值
    row_obj.password = md5('1129')
    row_obj.save()
    return render(request, 'error.html', {'msg': '数据重置成功,{}现在的密码为默认密码1129'.format(row_obj.username)})

  效果如下:

在这里插入图片描述

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
好的,这里提供一个简单的注册界面,使用 Django 自带的 `UserCreationForm` 实现注册功能,同时在前端显示提示消息: 1. 在 `views.py` 中定义视图函数: ```python from django.contrib.auth.forms import UserCreationForm from django.contrib.auth import authenticate, login from django.shortcuts import render, redirect def register(request): if request.method == 'POST': form = UserCreationForm(request.POST) if form.is_valid(): form.save() username = form.cleaned_data.get('username') password = form.cleaned_data.get('password1') user = authenticate(username=username, password=password) login(request, user) return redirect('index') else: form = UserCreationForm() return render(request, 'register.html', {'form': form}) ``` 2. 在 `urls.py` 中添加路由: ```python from django.urls import path from . import views urlpatterns = [ # ... path('register/', views.register, name='register'), # ... ] ``` 3. 在 `register.html` 模板中添加注册表单和提示消息: ```html {% extends 'base.html' %} {% block content %} <h2>Register</h2> <form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">Register</button> </form> {% if form.errors %} {% for error in form.errors %} <div class="error-message">{{ error }}</div> {% endfor %} {% endif %} {% if request.GET.next %} <input type="hidden" name="next" value="{{ request.GET.next }}" /> {% endif %} {% endblock %} ``` 这样,当用户在注册时,如果两次输入的密码不一致,表单就会显示对应的错误消息。如果注册成功,用户就会被重定向到首页。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铖铖的花嫁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值