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

发布于:2025-04-12 ⋅ 阅读:(64) ⋅ 点赞:(0)

【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

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

{% 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

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

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

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)

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到