python全栈开发day74-普通验证码和滑块验证码

一、昨日内容回顾

  django认证系统

  

1. 默认auth_user

```
    # 创建用户
    	from django.contrib.auth.models import User
        User.objects.create_user()
        User.objects.create_superuser(username=,password=...)
    # 去数据库校验用户名或密码是否正常,正确返回user对象,错误返回None
    	user = auth.authticate(username=...,password=...)
    # auth.login(request,user)
		# 1. 让当前用户登录,给cookie和session写入数据
        # 2. 这步操作执行之后,用户的浏览器有了cookie,session表里有了对应数据
        # session中根据cookie在session中找到user信息 ———》 user_obj/匿名用户
        # request.user = user_obj/匿名用户
    # auth.logout(request) # 退出登录删除session中的用户信息,利用request.session.flush()
    #   user = request.user
    	user.is_authticated()
    # 给登录认证加装饰器
    	from django.contrib.auth.decorators import login_required
    # from django.contrib.auth.models import User
       user = User.objects.create_user(username='',password='',email='')
       user = User.objects.create_superuser()
	# user = request.user
    user.check_password("旧密码")
    user.set_password("新密码")
    user.save()
```

2. 扩展默认auth_user
    from django.contrib.auth.models import AbstractUser
    class UserInfo(AbstractUser):
    	....
        ....
    AUTH_USER_MODEL = "app名.UserInfo"

  

二、今日内容总结

  1、Django ORM的三种模式:

    1)、使用默认的ManyToManyField创建第三张表:

      优势:

        可以使用ORM提供的快捷方法:

        add(),all(),clear(),set(),remove()

      劣势:不能扩展第三张表。  

from django.db import models

# Create your models here.


class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="书名")

    def __str__(self):
        return self.title


class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者姓名")
    books = models.ManyToManyField(to='Book')

    def __str__(self):
        return self.name
View Code

    2). 自己创建第三张关系表
      1. 优势:
        1. 可以自己扩展第三章关系表的字段(婚恋网站的男女用户的约会记录)
        2. 劣势:
      1. 不能使用ORM提供的快捷方法

from django.db import models

# Create your models here.


class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="书名")

    def __str__(self):
        return self.title


class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者姓名")

    def __str__(self):
        return self.name


# 自己创建多对多的第三张表
class Author2Book(models.Model):
    book = models.ForeignKey(to='Book')
    author = models.ForeignKey(to='Author')

    class Meta:
        unique_together = (('book', 'author'), )
View Code

    3). 自己创建第三张表,在ManyToManyField中通过through和through_fields指定表名和字段
      1. 优势:
        1. 可以使用ORM提供的部分快捷方法
          1. all()
        2. 可以扩展第三张关系表的字段

from django.db import models

# Create your models here.


class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="书名")

    def __str__(self):
        return self.title


class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者姓名")
    books = models.ManyToManyField(
        to='Book',
        through='Author2Book',
        through_fields=('author', 'book')
    )

    def __str__(self):
        return self.name


# 自己创建多对多的第三张表
class Author2Book(models.Model):
    book = models.ForeignKey(to='Book')
    author = models.ForeignKey(to='Author')

    class Meta:
        unique_together = (('book', 'author'), )
View Code

  2.bss项目验证码登录

    1. 登录页面实现及验证码布局

    2. 生成验证码图片
      1. pip install pillow
      from PIL import Image, ImageDraw, ImageFont
    3. 如何生成验证码?

    4. 验证码保存在哪里?

    5. 点击刷新验证码如何实现?  

from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from django import views
from blog.forms import LoginForm
from django.contrib.auth import authenticate, login, logout
# Create your views here.

V_CODE = ""


# 登录
class Login(views.View):

    def get(self, request):
        form_obj = LoginForm()
        return render(request, "login.html", {"form_obj": form_obj})

    def post(self, request):
        res = {"code": 0}
        print(request.POST)
        username = request.POST.get('username')
        pwd = request.POST.get('password')
        v_code = request.POST.get('v_code')
        print(v_code)
        print(V_CODE)
        # 先判断验证码是否正确
        if v_code.upper() != request.session.get("v_code", ""):
            res["code"] = 1
            res["msg"] = "验证码错误"
        else:
            # 校验用户名密码是否正确
            user = authenticate(username=username, password=pwd)
            if user:
                # 用户名密码正确
                login(request, user)
            else:
                # 用户名或密码错误
                res["code"] = 1
                res["msg"] = "用户名或密码错误"
        return JsonResponse(res)


# 首页
class Index(views.View):
    def get(self, request):
        return render(request, "index.html")


# 专门用来返回验证码图片的视图
def v_code(request):
    # 随机生成图片
    from PIL import Image, ImageDraw, ImageFont
    import random
    # 生成随机颜色的方法
    def random_color():
        return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
    # 生成图片对象
    image_obj = Image.new(
        "RGB",  # 生成图片的模式
        (250, 35),  # 图片大小
        random_color()
    )
    # 生成一个准备写字的画笔
    draw_obj = ImageDraw.Draw(image_obj)  # 在哪里写
    font_obj = ImageFont.truetype('static/font/kumo.ttf', size=28)  # 加载本地的字体文件

    # 生成随机验证码
    tmp = []
    for i in range(5):
        n = str(random.randint(0, 9))
        l = chr(random.randint(65, 90))
        u = chr(random.randint(97, 122))
        r = random.choice([n, l, u])
        tmp.append(r)
        # 每一次取到要写的东西之后,往图片上写
        draw_obj.text(
            (i*45+25, 0),  # 坐标
            r,  # 内容
            fill=random_color(),  # 颜色
            font=font_obj  # 字体
        )

    # # 加干扰线
    # width = 250  # 图片宽度(防止越界)
    # height = 35
    # for i in range(5):
    #     x1 = random.randint(0, width)
    #     x2 = random.randint(0, width)
    #     y1 = random.randint(0, height)
    #     y2 = random.randint(0, height)
    #     draw_obj.line((x1, y1, x2, y2), fill=random_color())
    #
    # # 加干扰点
    # for i in range(40):
    #     draw_obj.point([random.randint(0, width), random.randint(0, height)], fill=random_color())
    #     x = random.randint(0, width)
    #     y = random.randint(0, height)
    #     draw_obj.arc((x, y, x+4, y+4), 0, 90, fill=random_color())

    v_code = "".join(tmp)  # 得到最终的验证码
    # global V_CODE
    # V_CODE = v_code  # 保存在全局变量不行!!!
    # 将该次请求生成的验证码保存在该请求对应的session数据中
    request.session['v_code'] = v_code.upper()

    # 将上一步生成的图片保存在本地的static目录下
    # 每一次 都在硬盘中保存再读取都涉及IO操作,会慢
    # with open('static/oo.png', 'wb') as f:
    #     image_obj.save(f)
    #
    # with open('static/oo.png', "rb") as f:
    #     data = f.read()
    # 直接将生成的图片保存在内存中
    from io import BytesIO
    f = BytesIO()
    image_obj.save(f, "png")
    # 从内存读取图片数据
    data = f.getvalue()
    return HttpResponse(data, content_type="image/png")
验证码校验
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>

    <link type="text/css" rel='stylesheet' href="{% static 'bootstrap/dist/css/bootstrap.css' %}">
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-4 col-md-offset-4">
            <form action="/login/" method="post" class="form-horizontal" id="login_form">
                {% csrf_token %}
                <div class="form-group">
                    <label for="{{ form_obj.username.id_for_label }}">{{ form_obj.username.label }}</label>
                    {{ form_obj.username }}
                </div>
                <div class="form-group">
                    <label for="{{ form_obj.password.id_for_label }}">{{ form_obj.password.label }}</label>
                    {{ form_obj.password }}
                </div>
                <div class="form-group">
                    <label for="v_code" style="display: block">验证码</label>

                    <input type="text" id="v_code" class="form-control" style="display: inline-block; 180px">
                    <img src="/v_code/" id='img_check'  alt="" width="200px" height="35px" border="black solid 1px">

                </div>
                <p id="error-p" class="err-text"></p>
                <button id="login-btn" type="button" class="btn btn-default">登录</button>
            </form>
        </div>
    </div>
</div>
<script src="{% static 'jquery/jquery.js' %}"></script>
<script>
    $('#login-btn').click(function () {
        let password = $('#id_password').val();
        let username = $('#id_username').val();
        let csrf_token = $("[name='csrfmiddlewaretoken']").val();
        let v_code = $("#v_code").val()
        $.ajax({
            url: '/login/',
            type: 'post',
            data: {
                username: username,
                password: password,
                csrfmiddlewaretoken: csrf_token,
                v_code:v_code,
            },
            success: function (res) {
                if(res.code!==0){
                    $('#error-p').text(res.msg).css("color",'red')
                }else {
                    location.href='/index/'
                }
            }
        })
    })
    $('input').focus(function () {
        $('#error-p').text('');
    })
    $("#img_check").click(function () {
        this.src += '?';
    })

</script>
</body>
</html>
login.html

三、预习和扩展

1. 用%s还是format

  https://www.cnblogs.com/liwenzhou/p/8570701.html

相关推荐