【Django】:图片验证码、KindEditor

图片验证码

生成图片验证码需要以下:

  • session
  • check_code.py(依赖:Pillow,字体文件) 模块安装 pip install Pillow
  • src属性后面加?

在utils下拷贝check_code.py(用于生成图片验证码)文件

#!/usr/bin/env python
# -*- coding:utf-8 -*-

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

_letter_cases = "abcdefghjkmnpqrstuvwxy"  # 小写字母,去除可能干扰的i,l,o,z
_upper_cases = _letter_cases.upper()  # 大写字母
_numbers = ''.join(map(str, range(3, 10)))  # 数字
init_chars = ''.join((_letter_cases, _upper_cases, _numbers))


def create_validate_code(size=(120, 30),
                         chars=init_chars,
                         img_type="GIF",
                         mode="RGB",
                         bg_color=(255, 255, 255),
                         fg_color=(0, 0, 255),
                         font_size=18,
                         font_type="Monaco.ttf",
                         length=4,
                         draw_lines=True,
                         n_line=(1, 2),
                         draw_points=True,
                         point_chance=2):
    """
    @todo: 生成验证码图片
    @param size: 图片的大小,格式(宽,高),默认为(120, 30)
    @param chars: 允许的字符集合,格式字符串
    @param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG
    @param mode: 图片模式,默认为RGB
    @param bg_color: 背景颜色,默认为白色
    @param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF
    @param font_size: 验证码字体大小
    @param font_type: 验证码字体,默认为 ae_AlArabiya.ttf
    @param length: 验证码字符个数
    @param draw_lines: 是否划干扰线
    @param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效
    @param draw_points: 是否画干扰点
    @param point_chance: 干扰点出现的概率,大小范围[0, 100]
    @return: [0]: PIL Image实例
    @return: [1]: 验证码图片中的字符串
    """

    width, height = size  # 宽高
    # 创建图形
    img = Image.new(mode, size, bg_color)
    draw = ImageDraw.Draw(img)  # 创建画笔

    def get_chars():
        """生成给定长度的字符串,返回列表格式"""
        return random.sample(chars, length)

    def create_lines():
        """绘制干扰线"""
        line_num = random.randint(*n_line)  # 干扰线条数

        for i in range(line_num):
            # 起始点
            begin = (random.randint(0, size[0]), random.randint(0, size[1]))
            # 结束点
            end = (random.randint(0, size[0]), random.randint(0, size[1]))
            draw.line([begin, end], fill=(0, 0, 0))

    def create_points():
        """绘制干扰点"""
        chance = min(100, max(0, int(point_chance)))  # 大小限制在[0, 100]

        for w in range(width):
            for h in range(height):
                tmp = random.randint(0, 100)
                if tmp > 100 - chance:
                    draw.point((w, h), fill=(0, 0, 0))

    def create_strs():
        """绘制验证码字符"""
        c_chars = get_chars()
        strs = ' %s ' % ' '.join(c_chars)  # 每个字符前后以空格隔开

        font = ImageFont.truetype(font_type, font_size)
        font_width, font_height = font.getsize(strs)

        draw.text(((width - font_width) / 3, (height - font_height) / 3),
                  strs, font=font, fill=fg_color)

        return ''.join(c_chars)

    if draw_lines:
        create_lines()
    if draw_points:
        create_points()
    strs = create_strs()

    # 图形扭曲参数
    params = [1 - float(random.randint(1, 2)) / 100,
              0,
              0,
              0,
              1 - float(random.randint(1, 10)) / 100,
              float(random.randint(1, 2)) / 500,
              0.001,
              float(random.randint(1, 2)) / 500
              ]
    img = img.transform(size, Image.PERSPECTIVE, params)  # 创建扭曲

    img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)  # 滤镜,边界加强(阈值更大)

    return img, strs
check_code.py

templates下login.html文件

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" href="/static/plugins/bootstrap/css/bootstrap.css"/>
    <link rel="stylesheet" href="/static/plugins/font-awesome/css/font-awesome.css"/>
    <link rel="stylesheet" href="/static/css/edmure.css"/>
    <link rel="stylesheet" href="/static/css/commons.css"/>
    <link rel="stylesheet" href="/static/css/account.css"/>
    <style>

    </style>
</head>
<body>
<div class="login">
    <div style="font-size: 25px; font-weight: bold;text-align: center;">
        用户登陆
    </div>
    <form role="form" action="/login.html" method="POST">
        {% csrf_token %}
        <div class="form-group">
            <label for="username">用户名</label>
            <input type="text" class="form-control"  placeholder="请输入用户名">
        </div>
        <div class="form-group">
            <label for="password">密码</label>
            <input type="password" class="form-control"  placeholder="请输入密码">
        </div>
        <div class="form-group">
            <label for="password">验证码</label>

            <div class="row">
                <div class="col-xs-7">
                    <input type="text" class="form-control" placeholder="请输入验证码" name="check_code">
                </div>
                <div class="col-xs-5">
                    <img src="/check_code.html" onclick="changeCheckCode(this);">   <!--点击更换验证码-->
                </div>
            </div>

        </div>
        <div class="checkbox">
            <label>
                <input type="checkbox"> 一个月内自动登陆
            </label>
            <div class="right">
                <a href="#">忘记密码?</a>
            </div>
        </div>
        <button type="submit" class="btn btn-default">登 陆</button>
    </form>
</div>
    <script>
        function changeCheckCode(ths){
            ths.src = ths.src +  '?';   //刷新验证码
        }
    </script>
</body>
</html>
login.html

文件关键的两个点:

<div class="col-xs-5">
     <img src="/check_code.html" onclick="changeCheckCode(this);">   <!--点击更换验证码-->
</div>
<script>
    function changeCheckCode(ths){
      ths.src = ths.src +  '?';   //刷新验证码
    }
</script>

处理文件account.py

from io import BytesIO
from django.shortcuts import HttpResponse
from django.shortcuts import render
from utils.check_code import create_validate_code

def check_code(request):
    """
    验证码
    :param request:
    :return:
    """
    # 1. 创建一张图片 pip3 install Pillow
    # 2. 在图片中写入随机字符串
    # obj = object()
    # 3. 将图片写入到制定文件
    # 4. 打开制定目录文件,读取内容
    # 5. HttpResponse(data)

    stream = BytesIO()      #在内存中生成一个文件对象
    img, code = create_validate_code()  #生成图片img和字符串code
    img.save(stream,'PNG')      #把验证图片存放到内存中以PNG名存放
    request.session['CheckCode'] = code     #把生成的字符串code存放到session中
    print(code)
    return HttpResponse(stream.getvalue())      #stream.getvalue()返回图片的内容


def login(request):
    """
    登陆
    :param request:
    :return:
    """
    if request.method == 'GET':
        return render(request, 'login.html')
    elif  request.method == 'POST':
        # 此次省略用户名密码验证
        code = request.POST.get('check_code')
        if code.upper() == request.session['CheckCode'].upper():
            print('验证码正确')
            return HttpResponse('OK')
        else:
            print('验证码错误')
            return render(request, 'login.html')

上述操作可完成图片验证的认证 

KindEditor文件编辑器

1、进入官网

2、下载

  • 官网下载:http://kindeditor.net/down.php
  • 本地下载:http://files.cnblogs.com/files/wupeiqi/kindeditor_a5.zip

3、文件夹说明

├── asp                          asp示例         可删
├── asp.net                    asp.net示例     可删
├── attached                  空文件夹,放置关联文件attached   可删
├── examples                 HTML示例       可删
├── jsp                          java示例        可删
├── kindeditor-all-min.js 全部JS(压缩)
├── kindeditor-all.js        全部JS(未压缩)
├── kindeditor-min.js      仅KindEditor JS(压缩)
├── kindeditor.js            仅KindEditor JS(未压缩)
├── lang                        支持语言
├── license.txt               License
├── php                        PHP示例         可删
├── plugins                    KindEditor内部使用的插件
└── themes                   KindEditor主题

4、基本使用  

把下载的kind-editor文件拷贝到static目录下

<textarea name="content" id="content"></textarea>
 
<script src="/static/jquery-1.12.4.js"></script>
<script src="/static/plugins/kind-editor/kindeditor-all.js"></script>
<script>
    $(function () {
        initKindEditor();
    });
 
    function initKindEditor() {
        // 第一个参数id content 第二个参数字典 进行配置
        var kind = KindEditor.create('#content', {
             '100%',       // 文本框宽度(可以百分比或像素)
            height: '300px',     // 文本框高度(只能像素)
            minWidth: 200,       // 最小宽度(数字)
            minHeight: 400      // 最小高度(数字)
{#            items: ['superscript', 'clearhtml', 'quickformat', 'selectall'] ,// 配置工具栏#}
{#            noDisableItems: ["source", "fullscreen"],  // 得和designMode:false结合使用 表示只显示那些工具#}
{#            designMode: false,#}

        });
    }
</script>

重点:kind-editor的详细参数--》》http://kindeditor.net/docs/option.html

5、上传文件+文件空间管理

HTML文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<form>
    {% csrf_token %}
    <div style=" 500px;margin: 0 auto">
        <textarea id="content"></textarea>
    </div>
    <input type="submit" value="提交"/>
</form>

<script src="/static/jquery-1.12.4.js"></script>
<script src="/static/kindeditor-4.1.10/kindeditor-all.js"></script>
<script>
    $(function () {
        // 第一个参数id content 第二个参数字典 进行配置
        KindEditor.create('#content', {
            uploadJson: '/upload_img/',         // 上传地址 图片?dir=image 不同类型dir不一样
            fileManagerJson: '/file_manager/',     // 文件空间管理
            allowImageRemote: true,             // 是否允许上传远程图片
            allowImageUpload: true,            // 是否允许上传图片
            allowFileManager: true,
            extraFileUploadParams: {            // 这个比较重要,提交csrf_token
                csrfmiddlewaretoken: "{{ csrf_token }}"
            },
            filePostName: 'fafafa'              // 发送文件名
        });
    })
</script>
</body>
</html>

处理文件:

def kind(request):

    return render(request,'kind.html')

def upload_img(request):
    # 文件上传
    print(request.FILES)
# < MultiValueDict: {'fafafa': [ < InMemoryUploadedFile: 20170213143925.png(image / png) >]} >
    dic = {
        'error': 0,             # 0表示正确 1为错误
        'url': '/static/imgs/20170213143925.png',   #预览图片地址
        'message': '错误了...'
    }
    import json
    return HttpResponse(json.dumps(dic))

import os
import time
import json
def file_manager(request):
    """
    文件管理
    :param request:
    :return:
    """
    dic = {}
    root_path = 'C:/Users/L/PycharmProjects/Django项目'
    static_root_path = '/static/'
    request_path = request.GET.get('path')
    if request_path:
        abs_current_dir_path = os.path.join(root_path, request_path)
        move_up_dir_path = os.path.dirname(request_path.rstrip('/'))
        dic['moveup_dir_path'] = move_up_dir_path + '/' if move_up_dir_path else move_up_dir_path

    else:
        abs_current_dir_path = root_path
        dic['moveup_dir_path'] = ''

    dic['current_dir_path'] = request_path
    dic['current_url'] = os.path.join(static_root_path, request_path)

    file_list = []
    for item in os.listdir(abs_current_dir_path):
        abs_item_path = os.path.join(abs_current_dir_path, item)
        a, exts = os.path.splitext(item)
        is_dir = os.path.isdir(abs_item_path)
        if is_dir:
            temp = {
                'is_dir': True,
                'has_file': True,
                'filesize': 0,
                'dir_path': '',
                'is_photo': False,
                'filetype': '',
                'filename': item,
                'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(os.path.getctime(abs_item_path)))
            }
        else:
            temp = {
                'is_dir': False,
                'has_file': False,
                'filesize': os.stat(abs_item_path).st_size,
                'dir_path': '',
                'is_photo': True if exts.lower() in ['.jpg', '.png', '.jpeg'] else False,
                'filetype': exts.lower().strip('.'),
                'filename': item,
                'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(os.path.getctime(abs_item_path)))
            }

        file_list.append(temp)
    dic['file_list'] = file_list
    return HttpResponse(json.dumps(dic))

  

《第二十四章》

原文地址:https://www.cnblogs.com/lianzhilei/p/6394178.html