【Django】教程-14-验证码+登录页

【Django】教程-1-安装+创建项目+目录结构介绍
【Django】教程-2-前端-目录结构介绍
【Django】教程-3-数据库相关介绍
【Django】教程-4-一个增删改查的Demo
【Django】教程-5-ModelForm增删改查+规则校验【正则+钩子函数】
【Django】教程-6-搜索框-条件查询前后端
【Django】教程-7-分页,默认使用django的
【Django】教程-8-页面时间组件
【Django】教程-9-登录+退出
【Django】教程-10-ajax请求Demo,结合使用
【Django】教程-11-ajax弹窗实现增删改查
【Django】教程-12-柱状图
【Django】教程-13-饼图,折线图

19 .验证码+登录页

验证码工具类 captcha_utils.py

python 复制代码
from PIL import Image, ImageDraw, ImageFont
import random
import string


def generate_captcha(length=4, size=(120, 30), font_size=20):
    """ 一个可以返回验证码的,方法

    Returns:
            list:
             - image,验证码图
             - captcha_text,验证码字符串
    """
    # 定义验证码字符集
    characters = string.ascii_letters + string.digits

    # 随机生成验证码
    captcha_text = ''.join(random.choice(characters) for _ in range(length))

    # 创建一个彩色图像,背景颜色选择较浅的色调
    background_color = (
        random.randint(200, 255),
        random.randint(200, 255),
        random.randint(200, 255)
    )
    image = Image.new('RGB', size, color=background_color)
    draw = ImageDraw.Draw(image)

    # 选择字体
    font = ImageFont.load_default()
    # 也可以使用自定义字体,例如:
    # font = ImageFont.truetype('arial.ttf', font_size)

    # 绘制验证码字符,字体颜色选择较深的色调
    for i, char in enumerate(captcha_text):
        char_color = (
            random.randint(0, 100),
            random.randint(0, 100),
            random.randint(0, 100)
        )
        draw.text((10 + i * 25, 10), char, fill=char_color, font=font)

    # 添加干扰线
    for _ in range(5):
        line_color = (
            random.randint(150, 255),
            random.randint(150, 255),
            random.randint(150, 255)
        )
        x1 = random.randint(0, size[0])
        y1 = random.randint(0, size[1])
        x2 = random.randint(0, size[0])
        y2 = random.randint(0, size[1])
        draw.line((x1, y1, x2, y2), fill=line_color, width=2)

    # 添加干扰点
    for _ in range(20):
        point_color = (
            random.randint(150, 255),
            random.randint(150, 255),
            random.randint(150, 255)
        )
        x = random.randint(0, size[0])
        y = random.randint(0, size[1])
        draw.point((x, y), fill=point_color)

    return image, captcha_text

登录页 login.html

html 复制代码
{% load static %}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>登录页面</title>
    <!-- 引入 Bootstrap 的 CSS 文件 -->
    <link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.css' %}"/>

    <style>
        /* 自定义一些样式让页面更美观 */
        body {
            background-color: #f8f9fa;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
        }

        .login-card {
            background-color: white;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            padding: 2rem;
            width: 350px;
        }

        .form-group {
            margin-bottom: 1.5rem;
        }

        .form-control {
            height: calc(2.25rem + 2px);
        }

        .btn-login {
            width: 100%;
            padding: 0.75rem;
            background-color: #007bff;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }

        .btn-login:hover {
            background-color: #0056b3;
        }

        .register-link {
            text-align: center;
            margin-top: 1rem;
        }

        .register-link a {
            color: #007bff;
            text-decoration: none;
        }

        .register-link a:hover {
            text-decoration: underline;
        }
    </style>
</head>

<body>
<div class="container login-card">
    <h2 class="text-center mb-4">用户登录</h2>
    <form method="post" novalidate>
        {% csrf_token %}
        <div class="form-group">
            <label>用户名:</label>
            {{ user.username }}
            <span style="color: red">{{ user.username.errors.0 }}</span>
        </div>
        <div class="form-group">
            <label>密码:</label>
            {{ user.password }}
            <span style="color: red">{{ user.password.errors.0 }}</span>
        </div>

        <div class="form-group">
            <label>验证码:</label>
            <img  id="captcha-image" class="img-fluid" src="/captcha/get" >

            {{ user.captcha }}
            <span style="color: red">{{ user.captcha.errors.0 }}</span>

        </div>

        <button type="submit" class="btn-login">登录</button>
    </form>

    <div class="register-link">
        还没有账号?<a href="#">立即注册</a>
    </div>
</div>

<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.js' %}"></script>
<script>
    $(document).ready(function () {
        $('#captcha-image').click(function () {
            $.ajax({
                url: '/captcha/get',
                type: 'GET',
                success: function (response) {
                    $('#captcha-image').attr('src', '/captcha/get');
                    // 可以在这里清空验证码输入框
                    {#$('input[name="captcha"]').val('');#}
                },
                error: function () {
                    alert('刷新验证码失败');
                }
            });
        });
    });
</script>
</body>
</html>

业务控制层login_view.py

python 复制代码
import io

from django.http import HttpResponse, JsonResponse
from django.shortcuts import render, redirect
from django.views.decorators.csrf import csrf_exempt
from appTang.forms import LoginForm
from appTang.models import Admin
from appTang.util.captcha_utils import generate_captcha

def login(req):
   """用户登录"""
    """ modelform 方式添加用户"""
    if req.method == 'GET':
        user = LoginForm()
        return render(req, 'login/login.html', {"user": user})
    # 用户post提交,数据校验
    user = LoginForm(data=req.POST)
    if user.is_valid():
        # username = req.POST.get("username")
        username = user.clean_username()
        user = Admin.objects.filter(username=username).first()
        # 需要添加用户认证成功信息
        req.session["info"] = {"username": username, 'id': user.id}

        captcha = req.POST.get("captcha")
        image_code = req.session.get('captcha', '')  # 超时时,没有,给个''
        # 不区分大小写比较
        if image_code.upper() == captcha.upper():
            # 登录成功设置session,超时时间
            req.session.set_expiry(60 * 60 * 24 * 7)  # 7天免登录
            return redirect("/admin/list")
        else:
            user = LoginForm(data=req.POST)
            user.add_error('captcha', '验证码输入错误')
    # # 校验失败, 在页面上展示错误信息
    return render(req, 'login/login.html', {"user": user})


def logout(req):
    """注销"""
    req.session.clear();
    return redirect("/login/")

def get_captcha(request):
    """ 获取 验证码 """
    image, captcha_text = generate_captcha()
    # 将验证码存储在会话中
    request.session['captcha'] = captcha_text
    # 设置超时时间
    request.session.set_expiry(60)

    # 将图片保存到内存中
    buffer = io.BytesIO()
    image.save(buffer, 'PNG')
    # buffer.seek(0)
    print(captcha_text)
    # 返回图片响应
    return HttpResponse(buffer.getvalue())

forms.py

python 复制代码
from django import forms
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator

from . import models
from .models import Department, UserInfo, Admin, Order
from .util.md5 import md5


class BootstrapModelForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 循环Modelform中所有字段,给每个字段插件设置
        for name, field in self.fields.items():
            if field.widget.attrs:
                field.widget.attrs["class"] = "form-control"
                field.widget.attrs["placeholder"] = field.label
            else:
                field.widget.attrs = {"class": "form-control", "placeholder": field.label}

# 登录Form
class LoginForm(BootstrapModelForm):
    captcha = forms.CharField(label="验证码", widget=forms.TextInput())
    class Meta:
        model = Admin
        # 字段按照顺序加载
        fields = ['username', 'password', 'captcha']
        widgets = {
            "password": forms.PasswordInput(render_value=True)
        }
    def clean_username(self):
        username = self.cleaned_data.get("username")
        if not Admin.objects.filter(username=username).exists():
            # raise ValidationError("用户名不存在!")
            raise ValidationError("用户名或密码错误!")
        return username
    def clean_password(self):
        password = self.cleaned_data.get("password")
        username = self.cleaned_data.get("username")
        if not Admin.objects.filter(username=username, password=md5(password)).exists():
            # raise ValidationError("密码不正确!")
            raise ValidationError("用户名或密码错误!")
        return md5(password)

models.py

python 复制代码
from django.utils import timezone
from django.db import models

class Admin(models.Model):
    """管理员"""
    username = models.CharField(verbose_name="用户名", max_length=32)
    password = models.CharField(verbose_name="密码", max_length=64)
相关推荐
qq_2290580115 小时前
运行djando项目 配置启动类 label_studio包含前后端启动方法
python·django
码界奇点18 小时前
基于Python与Django的白泽自动化运维系统设计与实现
运维·python·django·毕业设计·源代码管理
计算机毕业编程指导师18 小时前
【Python大数据选题】基于Spark+Django的电影评分人气数据可视化分析系统源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习
大数据·hadoop·python·计算机·spark·django·电影评分人气
Python极客之家19 小时前
基于Django的高校二手市场与社交系统
后端·python·数据挖掘·django·毕业设计
码界奇点20 小时前
基于Django与Zabbix集成的运维故障管理系统设计与实现
运维·django·毕业设计·zabbix·源代码管理
码界奇点20 小时前
基于Django与Ansible的自动化运维管理系统设计与实现
运维·python·django·毕业设计·ansible·源代码管理
U盘失踪了20 小时前
Django 学生成绩管理系统
django
倔强青铜三3 天前
Django 6.0来袭!这些新特性,真的令人振奋!
人工智能·python·django
Java水解4 天前
Django实现接口token检测的实现方案
后端·django
飞Link4 天前
【Django】Django 调用外部 Python 程序的完整指南
后端·python·django·sqlite