数据库设计

from django.db import models
from django.contrib.auth.models import AbstractUser

class UserInfo(AbstractUser):
    """
    用户信息,继承auth_user表
    """
    nid = models.AutoField(primary_key=True)
    nickname = models.CharField(verbose_name='昵称', max_length=32)
    telephone = models.CharField(max_length=11, null=True, unique=True)
    avatar = models.FileField(upload_to='avatar/', default="/avatar/default.png")
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
    blog = models.OneToOneField(to='Blog', to_field='nid', null=True)

    def __str__(self):
        return self.username

class Blog(models.Model):
    """
    博客信息
    """
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name='个人博客标题', max_length=64)
    site = models.CharField(verbose_name='个人博客后缀', max_length=32, unique=True)
    theme = models.CharField(verbose_name='博客主题', max_length=32)

    def __str__(self):
        return self.title

class HomeCategory(models.Model):
    """
    博主个人文章分类表
    """
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name='分类标题', max_length=32)
    blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid')

    def __str__(self):
        return self.title

class Tag(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name='标签名称', max_length=32)
    blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid')

class Article(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=50, verbose_name='文章标题')
    desc = models.CharField(max_length=255, verbose_name='文章描述')

    comment_count = models.IntegerField(default=0)
    up_count = models.IntegerField(default=0)
    down_count = models.IntegerField(default=0)

    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)

    homeCategory = models.ForeignKey(to='HomeCategory', to_field='nid', null=True)
    user = models.ForeignKey(verbose_name='作者', to='UserInfo', to_field='nid')
    tags = models.ManyToManyField(
        to="Tag",
        through='Article2Tag',
        through_fields=('article', 'tag'),
    )

    def __str__(self):
        return self.title

class Article2Tag(models.Model):
    nid = models.AutoField(primary_key=True)
    article = models.ForeignKey(verbose_name='文章', to="Article", to_field='nid')
    tag = models.ForeignKey(verbose_name='标签', to="Tag", to_field='nid')

    class Meta:
        unique_together = [
            ('article', 'tag'),
        ]

class ArticleDetail(models.Model):
    """
    文章详细表
    """
    nid = models.AutoField(primary_key=True)
    content = models.TextField()

    article = models.OneToOneField(to='Article', to_field='nid')

class Comment(models.Model):
    """
    评论表
    """
    nid = models.AutoField(primary_key=True)
    article = models.ForeignKey(verbose_name='评论文章', to='Article', to_field='nid')
    user = models.ForeignKey(verbose_name='评论者', to='UserInfo', to_field='nid')
    content = models.CharField(verbose_name='评论内容', max_length=255)
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)

    parent_comment = models.ForeignKey('self', null=True)

    def __str__(self):
        return self.content

class ArticleUpDown(models.Model):
    """
    点赞表
    """
    nid = models.AutoField(primary_key=True)
    user = models.ForeignKey('UserInfo', null=True)
    article = models.ForeignKey("Article", null=True)
    is_up = models.BooleanField(default=True)

    class Meta:
        unique_together = [
            ('article', 'user'),
        ]

models.py

验证码登录

先打个样儿:

part1:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <title>Title</title>
    <link rel="stylesheet" href="/static/plugins/bootstrap/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/css/login.css">

<body>

<div class="container ">
    <div class="row ">
        <form action="" class="form-horizontal col-md-6 col-md-offset-3">
            <div class="form-group">
                <label for="username">用户名</label>
                <input type="text" class="form-control" id="username">
            </div>

            <div class="form-group">
                <label for="password">密码</label>
                <input type="password" class="form-control" id="password">
            </div>

            <div class="form-group">
                <label for="valid_code">验证码</label>
                <div class="row">
                    <div class="col-md-6">
                        <input type="text" class="form-control" id="valid_code">
                    </div>
                    <div class="col-md-6">
                        <img width="230" height="35" src="https://pic.cnblogs.com/avatar/1054809/20171214142056.png"
                             alt="">
                    </div>
                </div>

            </div>
            <div class="form-group">
                <input type="button" value="登录" class="btn btn-primary form-control" id="login-btn">

            </div>

        </form>
    </div>
</div>

<script src="/static/js/jquery-3.2.1.min.js"></script>
<script src="/static/plugins/bootstrap/js/bootstrap.min.js"></script>
</body>
</html> 

login.html

.container{
    margin-top: 100px;
}

login.css

看先效果:

导入 PIL模块,random模块。生成随机颜色的验证图。(PIL需要安装pillow模块:pip install pillow)

login.html
 <img src="/get_valid_img/" alt="" width="230" height="35" id="valid_img">
from django.shortcuts import render, redirect, HttpResponse
import random
from PIL import Image

def log_in(request):
    return render(request, 'login.html')

def get_valid_img(request):
    import random
    from PIL import Image
    def get_random_color():
        # 生成随机色
        return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))

    # 生成图片(画布,默认是白色)
    image = Image.new(mode="RGB", size=(230, 35), color=get_random_color())
    f = open('a.png', 'wb')
    image.save(f, 'png')
    # 读取图片数据
    with open('a.png', 'rb') as f_read:
        data = f_read.read()
    return HttpResponse(data)

views.py

我们当然不能用图片来当验证码,而且还有一个问题是,图片也不能保存在硬盘上。

还需要导入下面的模块

from PIL import ImageDraw,ImageFont (画笔和字体)
from io import BytesIO(用于将图片暂存在内存)

字体文件:http://oyh98v0ft.bkt.clouddn.com/kumo.ttf

from django.shortcuts import render, redirect, HttpResponse
import random
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO
from PIL import Image

def log_in(request):
    return render(request, 'login.html')

def get_valid_img(request):
    def get_random_color():
        # 生成随机色
        return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))

    def get_random_char():
        # 生成随机字符
        random_num = str(random.randint(0, 9))  # 随机数字
        random_upper_alph = chr(random.randint(65, 90))  # 随机大写字母
        random_lowwer_alph = chr(random.randint(79, 122))  # 随机小写字母
        random_char = random.choice([random_num, random_lowwer_alph, random_upper_alph])
        return random_char  # 返回随机字符

    # 生成画布图片
    image = Image.new(mode="RGB", size=(230, 35), color=get_random_color())
    # 生成画笔
    draw = ImageDraw.Draw(image, mode="RGB")
    # 指定字体
    font = ImageFont.truetype("blog/static/font/kumo.ttf", 32)
    # 写入6个随机字符(数字,字母)
    for i in range(1, 6):
        char = get_random_char()
        draw.text([i * 40, 5], char, get_random_color(), font=font)
    width = 230
    height = 35
    # 生成80个点
    for i in range(80):
        draw.point((random.randint(0, width), random.randint(0, height)), fill=get_random_color())
    # 生成两根干扰线
    for i in range(2):
        x1 = random.randint(0, width)
        x2 = random.randint(0, width)
        y1 = random.randint(0, height)
        y2 = random.randint(0, height)
        draw.line((x1, y1, x2, y2), fill=get_random_color())
    # 暂存内存
    f = BytesIO()
    image.save(f, "png")
    # 从内存中取
    data = f.getvalue()
    return HttpResponse(data)

views.py

给img添加点击局部刷新的功能:

img标签很特别,不需要ajax,如下。

<script>
         $("#valid_img").click(function () {
         $(this)[0].src+="?"
     });
</script>

  

验证码初步完成,下面完成登录验证功能。

因为要验证验证码是否输入正确,我需要找一个容器存验证码,到后台去对比,这个容器就是session!

下面,看我操作

from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),

    url(r'^blog/', include('blog.urls')),
    url(r'^', include('blog.urls')),
]

mysit.urls.py

from django.conf.urls import url, include
from . import views

urlpatterns = [

    # 登录
    url(r'^login/$', views.log_in),
    # 验证码
    url(r'^get_valid_img/$', views.get_valid_img, name='get_valid_img'),
    # 主页
    url(r'^index/$', views.index, name='index'),

]

blog.urls.py

login.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <title>Title</title>
    <link rel="stylesheet" href="/static/plugins/bootstrap/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/css/login.css">

<body>

<div class="container ">
    <div class="row ">
        <form action="" class="form-horizontal col-md-6 col-md-offset-3">
            {% csrf_token %}
            <div class="form-group">
                <label for="username">用户名</label>
                <input type="text" class="form-control" id="username">
            </div>

            <div class="form-group">
                <label for="password">密码</label>
                <input type="password" class="form-control" id="password">
            </div>

            <div class="form-group">
                <label for="valid_code">验证码</label>
                <div class="row">
                    <div class="col-md-6">
                        <input type="text" class="form-control" id="valid_code">
                    </div>
                    <div class="col-md-6">
                        <img src="/get_valid_img/" alt="" width="230" height="35" id="valid_img">
                    </div>
                </div>

            </div>
            <div class="form-group">
                <input type="button" value="登录" class="btn btn-primary form-control" id="loginBtn">

            </div>

        </form>
        <span id="error_msg"></span>
    </div>
</div>

<script src="/static/js/jquery-3.2.1.min.js"></script>
<script src="/static/plugins/bootstrap/js/bootstrap.min.js"></script>

<script>
    // 局部刷新验证码
    $("#valid_img").click(function () {
        $(this)[0].src += "?"
    });
    //ajax 登录
    $("#loginBtn").click(function () {
        $.ajax({
            url: '/login/',
            type: 'POST',
            data: {
                csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(),
                username: $("#username").val(),
                password: $("#password").val(),
                valid_code: $("#valid_code").val()

            },
            success: function (data) {
                // 验证通过,进入主页
                if (data.user) {
                    location.href = '/index/'

                }
                // 验证不通过,就提示错误信息
                else {
                    $("#error_msg").text(data.error_msg).css("color", "red")
                    // 定时清除错误信息,8秒钟
                    setTimeout(function () {
                        $("#error_msg").text("")
                    }, 8000)
                }
            }

        })
    });
</script>
</body>
</html> 

views.py

from django.shortcuts import render, redirect, HttpResponse
import random
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO
from PIL import Image
from django.contrib import auth
from django.http import JsonResponse

def get_valid_img(request):
    def get_random_color():
        # 生成随机色
        return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))

    def get_random_char():
        # 生成随机字符
        random_num = str(random.randint(0, 9))  # 随机数字
        random_upper_alph = chr(random.randint(65, 90))  # 随机大写字母
        random_lowwer_alph = chr(random.randint(79, 122))  # 随机小写字母
        random_char = random.choice([random_num, random_lowwer_alph, random_upper_alph])
        return random_char  # 返回随机字符

    # 生成画布图片
    image = Image.new(mode="RGB", size=(230, 35), color=get_random_color())
    # 生成画笔
    draw = ImageDraw.Draw(image, mode="RGB")
    # 指定字体
    font = ImageFont.truetype("blog/static/font/kumo.ttf", 32)
    valid_code_str = ""  # 用来拼接验证码
    # 写入6个随机字符(数字,字母)
    for i in range(1, 6):
        char = get_random_char()
        valid_code_str += char  # 拼接验证码
        draw.text([i * 40, 5], char, get_random_color(), font=font)
    width = 230
    height = 35
    # 生成80个点
    for i in range(80):
        draw.point((random.randint(0, width), random.randint(0, height)), fill=get_random_color())
    # 生成两根干扰线
    for i in range(2):
        x1 = random.randint(0, width)
        x2 = random.randint(0, width)
        y1 = random.randint(0, height)
        y2 = random.randint(0, height)
        draw.line((x1, y1, x2, y2), fill=get_random_color())
    # 暂存内存
    f = BytesIO()
    image.save(f, "png")
    # 从内存中取
    data = f.getvalue()
    # 将验证码保存在session
    request.session["valid_code_str"] = valid_code_str
    return HttpResponse(data)

def log_in(request):
    if request.is_ajax():
        user = request.POST.get('username')
        pwd = request.POST.get('pwd')
        valid_code = request.POST.get('valid_code')
        # 获取session里面的验证码
        valid_code_str = request.session.get("valid_code_str")
        # 也可以这样写:valid_code_str=request.session["valid_code_str"]
        loginResponse = {"user": None, "error_msg": ''}
        # 先对验证码进行校验(不区分大小写)
        if valid_code_str.upper() == valid_code.upper():
            # 验证码通过,再对用户名密码进行校验(要导入auth)
            user = auth.authenticate(username=user, password=pwd)
            if user:
                auth.login(request, user)  # 设置session
                loginResponse["user"] = user.username
            else:
                loginResponse["error_msg"] = "username or password is wrong!"
        else:
            # 验证码不通过,不再进行下面的验证,直接返回提示错误信息
            loginResponse["error_msg"] = " valid code is wrong!"
            # JsonResponse可完成json数据的转换工作,简便!
        return JsonResponse(loginResponse)

    return render(request, 'login.html')

def index(request):
    return render(request, 'index.html')

效果:

验证码错误时:

验证码正确时(密码也错误)

美化版:

login.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <title>Title</title>
    <link rel="stylesheet" href="/static/plugins/bootstrap/css/bootstrap.min.css">
    <style>
        body {
            background-color: #eeeeee;
            margin-top: 100px;
        }
    </style>
<body>

<div class="container ">
    <div class="row ">
        <div class=" col-sm-6 col-sm-offset-3">
            <form action="" class="form-horizontal">
                {% csrf_token %}
                <div class="form-group">
                    <label for="username" class="col-sm-2 control-label">用户名</label>
                    <div class="col-sm-10">
                        <input type="text" class="form-control" id="username" placeholder="Username">
                    </div>
                </div>

                <div class="form-group">
                    <label for="password" class="col-sm-2 control-label">密码</label>
                    <div class="col-sm-10">
                        <input type="password" class="form-control" id="password" placeholder="Password">
                    </div>

                </div>

                <div class="form-group">
                    <label for="valid_code" class="col-sm-2 control-label">验证码</label>
                    <div class="col-sm-5">
                        <input type="text" class="form-control" id="valid_code" placeholder="Validcode">
                    </div>
                    <div class="col-sm-5">
                        <img style="margin-left: -17px" src="/get_valid_img/" alt="" width="230" height="33"
                             id="valid_img">
                    </div>
                </div>

                <div class="form-group">
                    <div class="col-sm-offset-2 col-sm-10">
                        <input type="button" value="登录" class="btn btn-primary form-control" id="loginBtn">
                    </div>
                </div>
                <div class="col-sm-offset-2 col-sm-10">
                    <div class="reg" style="margin-left: -10px">还没账号?<a href="/register/">立即注册</a></div>
                </div>

            </form>
        </div>
        <span id="error_msg"></span>
    </div>
</div>

<script src="/static/js/jquery-3.2.1.min.js"></script>
<script src="/static/plugins/bootstrap/js/bootstrap.min.js"></script>

<script>
    // 局部刷新验证码
    $("#valid_img").click(function () {
        $(this)[0].src += "?"
    });
    //ajax 登录
    $("#loginBtn").click(function () {
        $.ajax({
            url: '/login/',
            type: 'POST',
            data: {
                csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(),
                username: $("#username").val(),
                password: $("#password").val(),
                valid_code: $("#valid_code").val()

            },
            success: function (data) {
                // 验证通过,进入主页
                if (data.user) {
                    location.href = '/index/'

                }
                // 验证不通过,就提示错误信息
                else {
                    $("#error_msg").text(data.error_msg).css("color", "red")
                    // 定时清除错误信息,8秒钟
                    setTimeout(function () {
                        $("#error_msg").text("")
                    }, 8000)
                }
            }

        })
    });
</script>
</body>
</html> 

login.html

Django 博客项目01 数据库设计与验证码校验+Ajax登录的更多相关文章

  1. django博客项目8:文章详情页

    首页展示的是所有文章的列表,当用户看到感兴趣的文章时,他点击文章的标题或者继续阅读的按钮,应该跳转到文章的详情页面来阅读文章的详细内容.现在让我们来开发博客的详情页面,有了前面的基础,开发流程都是一样 ...

  2. django博客项目3:创建 Django 博客的数据库模型

    设计博客的数据库表结构 博客最主要的功能就是展示我们写的文章,它需要从某个地方获取博客文章数据才能把文章展示出来,通常来说这个地方就是数据库.我们把写好的文章永久地保存在数据库里,当用户访问我们的博客 ...

  3. Django——博客项目

    博客项目 目前的目标是构建一个基于Django的前后端完整的博客系统,首先对项目流程整理如下: 1. 分析需求 1.1. 基于用户认证组件和Ajax实现登录验证 图形验证码核心代码: 模板: < ...

  4. django博客项目5:博客首页视图(2)

    真正的 Django 博客首页视图 在此之前我们已经编写了 Blog 的首页视图,并且配置了 URL 和模板,让 Django 能够正确地处理 HTTP 请求并返回合适的 HTTP 响应.不过我们仅仅 ...

  5. 9.28 Django博客项目(一)

    2018-9-28 17:37:18 今天把博客项目 实现了注册和添加图片的功能! 放在了自己的github上面 源码! https://github.com/TrueNewBee/bbs_demo ...

  6. django博客项目6:Django Admin 后台发布文章

    在此之前我们完成了 Django 博客首页视图的编写,我们希望首页展示发布的博客文章列表,但是它却抱怨:暂时还没有发布的文章!如它所言,我们确实还没有发布任何文章,本节我们将使用 Django 自带的 ...

  7. django博客项目2.建立 Django 博客应用

    建立博客应用 我们已经建立了 Django 博客的项目工程,并且成功地运行了它.不过到目前为止这一切都还只是 Django 为我们创建的项目初始内容,Django 不可能为我们初始化生成博客代码,这些 ...

  8. django博客项目1.环境搭建

    安装 Python Windows 下安装 Python 非常简单,去 Python 官方网站找到 Python 3 的下载地址,根据你的系统选择 32 位或者 64 位的安装包,下载好后双击安装即可 ...

  9. <Django>博客项目

    0.项目的通用流程 项目立项 需求分析 原型 前端 页面设计 UI及交互实现 后端 架构设计 数据库设计 代码模板实现 单元测试 网站整合 功能及集成测试 网站发布 1.BBS项目需求分析 需要哪些表 ...

随机推荐

  1. java并发编程:线程安全管理类--原子操作类--AtomicLongFieldUpdater<T>

    1.类 AtomicLongFieldUpdater<T> public abstract class AtomicLongFieldUpdater<T> extends Ob ...

  2. BZOJ1907 树的路径覆盖

    ydc题解上写着贪心,后来又说是树形dp...可惜看不懂(顺便骗三连) 其实就是每个叶子开始拉一条链,从下面一路走上来,遇到能把两条链合起来的就合起来就好了. /******************* ...

  3. 数据仓库建模与ETL的实践

    一.Data仓库的架构 Data仓库(Data Warehouse DW)是为了便于多维分析和多角度展现而将Data按特定的模式进行存储所建立起来的关系型Datcbase,它的Data基于OLTP源S ...

  4. String类型的注意事项

    1.string类型是可变长字符序列,而vector是集合,存放的是某种类型的可变长序列 2.string类型对象的初始化有多种方式:string str="Hello",是将字符 ...

  5. if...then

    我到现在明白一些道理 有些事情是徒劳无功的 有些却不是 世间事不过如此,只要你肯付出相应的代价,你就可以得到.

  6. 一個不錯的免費流程圖制作軟件 Download link

    The process flow software you saw yesterday which is a free software, but you need to register. Down ...

  7. php 特殊字符

    今天碰到一个处理文件特殊字符的事情,再次注意到这个问题,在php中: * 以单引号为定界符的php字符串,支持两个转义\'和\\ * 以双引号为定界符的php字符串,支持下列转义:     \n 换行 ...

  8. 配置thunderbirdmail

    添加帐号 打开Edit→Account Settings ,选择左下放的 "Account actions"→"Add Mail Account". 在弹出框中 ...

  9. E - 追求

    经历了那晚的竹林深处相识后静竹对数学念念不忘,产生了好感!为了追求数学,她想到了一招,要想搞定女友,搞定闺中密友.于是,她秘密与数学的好友斐波那契见面了.学数学的真是不一样,斐波那契的出现前提也是需要 ...

  10. [Linux] diff命令:逐行进行文件比较

    1. 比较文件 $ diff file1 file2 2. 比较文件夹 $ diff -urNa dir1 dir2 -u, -U NUM, --unified[=NUM] output NUM (d ...