【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)
相关推荐
hanxiuchao3 天前
告别客户端臃肿!网页端 M3U8 播放调试方案,适配全办公场景
运维·python·django·m3u8·m3u8播放
程序员羽痕3 天前
基于深度学习的眼疾识别系统
人工智能·pytorch·深度学习·分类·django
流云鹤4 天前
1. 配置环境、创建导航栏
python·django
流云鹤4 天前
2.登录模块
python·django
流云鹤4 天前
专题栏说明
python·django
XGeFei5 天前
【Django学习笔记】—— Django 高并发通俗讲解
笔记·学习·django
weixin_BYSJ19875 天前
springboot美食食谱小程序---附源码24044
java·spring boot·python·spring cloud·django·tomcat·php
许彰午6 天前
87_Python Django模型与数据库
数据库·python·django
weixin_BYSJ19877 天前
SpringBoot + MySQL 乒乓球运动员信息管理系统项目实战--附源码04954
java·javascript·spring boot·python·django·flask·php
Database_Cool_8 天前
RAG 混合检索首选:阿里云 Lindorm 向量+全文一体化检索
数据库·阿里云·django·云计算