python django 实现带图片验证码的网站登录功能

django 实现带图片验证码的网站登录功能

  • 1 创建django项目和所需数据库及应用
  • 2 修改setting.py配置文件
  • 3 修改project/urls.py配置
  • 4 修改app01/urls.py配置
  • 5 修改app01/models.py配置
  • 6 新增app01/forms.py文件
  • 7 创建utils目录,并在目录下创建code.py文件,其中utils目录和app01同级目录
  • 8 导入字体文件
  • 9 修改app01/views.py文件
  • 10 增加app01/templates/register.html文件
  • 11 数据库迁移并生成数据表
  • 12 数据库插入数据
  • 13 运行项目
  • 14 页面显示
  • 15 参考博客

1 创建django项目和所需数据库及应用

# 1 创建数据库project
mysql -uroot -p123456
create database project default charset utf8;

# 2 创建项目project
django-admin startproject project

# 3 安装所需三方库
pip install django==3.2.13
pip install pillow==8.4.0
pip install pymysql

# 4 创建应用app01
cd project
python manage.py startapp app01

2 修改setting.py配置文件

# 添加app01应用
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',  # 新增
]

# 添加数据库配置
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'project',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': '192.168.144.3',
        'PORT': '3306',
    }
}

# 静态文件配置
STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
]

3 修改project/urls.py配置

from django.contrib import admin
from django.urls import path, include, re_path

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', include('app01.urls')),
]

4 修改app01/urls.py配置

from django.urls import path, include, re_path
from . import views

urlpatterns = [
    path('', views.MyClassView.as_view()),
    path('image/code/', views.ImageCode.as_view()),
]

5 修改app01/models.py配置

from django.db import models


class LoginDatabase(models.Model):
    username = models.CharField(verbose_name="用户名", max_length=32)
    password = models.CharField(verbose_name="密码", max_length=32)

    class Meta:
        db_table = 'login'

    def __str__(self):
        return self.username

6 新增app01/forms.py文件

from django import forms
from . import models
from django.forms import widgets


class LoginModelForm(forms.ModelForm):
    verify_code = forms.CharField(
        label='验证码',
        widget=forms.TextInput(attrs={'class': "form-control"})
    )

    class Meta:
        model = models.LoginDatabase
        fields = "__all__"

        labels = {"username": "名字", "password": "密码", "verify_code ": "验证码"}
        widgets = {
            # 不同类型的字段要用不同的属性输出,不然表单的格式验证失效
            # 给不同字段添加class属性,改变样式
            "username": widgets.TextInput({"class": "form-control"}),
            "password": widgets.PasswordInput({"class": "form-control"}),
        }
        error_messages = {"password": {"invalid": "请填写正确的密码格式"}}

    # def __init__(self, *args, **kwargs):
    #     super().__init__(*args, **kwargs)
    #     print(self.fields)
    #     for name, filed in self.fields.items():
    #         filed.widget.attrs = {"class": "form-control", "placeholder": filed.label}

7 创建utils目录,并在目录下创建code.py文件,其中utils目录和app01同级目录

(1)目录结构
python django 实现带图片验证码的网站登录功能_第1张图片
(2)utils/code.py

from PIL import Image,ImageDraw,ImageFilter,ImageFont
import random


def check_code(width=140, height=40, char_length=4, font_file='kumo.ttf', font_size=28):
    code = []
    img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
    draw = ImageDraw.Draw(img, mode='RGB')

    def rndChar():
        """
        生成随机字母
        :return:
        """
        return chr(random.randint(65, 90))

    def rndColor():
        """
        生成随机颜色
        :return:
        """
        return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))

    # 写文字
    font = ImageFont.truetype(font_file, font_size)
    for i in range(char_length):
        char = rndChar()
        code.append(char)
        h = random.randint(2, 6)
        draw.text([i * width / char_length, h], char, font=font, fill=rndColor())
        # draw.text([i * width / char_length, h], char, fill=rndColor(), font_size=150)

    # 写干扰点
    # for i in range(40):
    #     draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())

    # 写干扰圆圈
    # for i in range(40):
    #     draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
    #     x = random.randint(0, width)
    #     y = random.randint(0, height)
    #     draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())

    # 画干扰线
    # for i in range(5):
    #     x1 = random.randint(0, width)
    #     y1 = random.randint(0, height)
    #     x2 = random.randint(0, width)
    #     y2 = random.randint(0, height)
    #
    #     draw.line((x1, y1, x2, y2), fill=rndColor())

    img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
    return img, ''.join(code)


if __name__ == '__main__':
    pass
    img, code_str = check_code()
    print(img,code_str)
    with open('code.png', 'wb') as f:
        img.save(f, format='png')

    # 1. 直接打开
    # img,code = check_code()
    # img.show()

    # 2. 写入文件
    # img,code = check_code()
    # with open('code.png','wb') as f:
    #     img.save(f,format='png')

    # 3. 写入内存(Python3)
    # from io import BytesIO
    # stream = BytesIO()
    # img.save(stream, 'png')
    # stream.getvalue()

    # 4. 写入内存(Python2)
    # import StringIO
    # stream = StringIO.StringIO()
    # img.save(stream, 'png')
    # stream.getvalue()

8 导入字体文件

字体文件链接:点击这里

使用 kumo.ttf 字体文件存放目录和app01同级

python django 实现带图片验证码的网站登录功能_第2张图片

9 修改app01/views.py文件

from django.shortcuts import render, HttpResponse, redirect
from django.views.generic import View
from . import forms, models
from io import BytesIO
from utils.code import check_code


class MyClassView(View):
    """类视图"""
    def get(self, request):
        """处理GET请求"""
        form = forms.LoginModelForm()
        # print(request.session.get('image_code'))
        return render(request, 'register.html', {'form': form})

    def post(self, request):
        """处理POST请求"""

        form = forms.LoginModelForm(data=request.POST)

        if form.is_valid():

            verify_code = form.cleaned_data.pop('verify_code')
            data = models.LoginDatabase.objects.filter(**form.cleaned_data).first()

            if data and (verify_code == request.session.get('image_code')):
                return redirect('https://www.baidu.com')
            else:
                form.add_error('password', '用户名或密码错误')
                return render(request, 'register.html', {'form': form})

        return render(request, 'register.html', {'form': form})


class ImageCode(View):

    def get(self, request):
        img, code_str = check_code()
        stream = BytesIO()
        img.save(stream, 'png')
        request.session['image_code'] = code_str

        request.session.set_expiry(60)
        #  stream.getvalue() 写入内存
        return HttpResponse(stream.getvalue())

10 增加app01/templates/register.html文件

{% load static %}
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
     <link href="https://fastly.jsdelivr.net/npm/@bootcss/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .navbar{
            border-radius: 0;
        }
        .account {
            width: 400px;
            border: 1px solid #dddddd;
            border-radius: 5px;
            box-shadow: 5px 5px 20px #aaa;
            margin-left: auto;
            margin-right: auto;
            margin-top: 100px;
            padding: 20px 40px;
        }
        .account h2 {
            margin-top: 10px;
            text-align: center;
        }

    style>
head>
<body>


<div class="account">
    <h2>用户登录h2>
    <form method="post" novalidate>
        {% csrf_token %}
        <div class="form-group">
            <label>用户名label>
            {{ form.username }}
            <span>{{ form.username.errors.0 }}span>
        div>
        <div class="form-group">
            <label>密码label>
            {{ form.password }}
            <span>{{ form.password.errors.0 }}span>
        div>

        <div class="form-group">
            <label >图片验证码label>
            <div class="row">
                <div class="col-xs-7">
                    {{ form.verify_code }}
                        <span>{{ form.verify_code.errors.0 }}span>
                    <span style="color: red;">span>
                div>
                <div class="col-xs-5">

                    <img id="image_code" src="/login/image/code/" alt="" style="width: 125px;">

                div>
            div>
        div>
        <input type="submit" value="登录" class="btn btn-primary">

    form>

div>

    <script src="https://fastly.jsdelivr.net/npm/@bootcss/[email protected]/dist/js/bootstrap.min.js">script>
    <script src="https://fastly.jsdelivr.net/npm/[email protected]/dist/jquery.min.js">script>
    <script src="https://fastly.jsdelivr.net/npm/[email protected]/dist/jquery.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous">script>
    <script>window.jQuery || document.write('
                    
                    

你可能感兴趣的:(django,python,django,后端)