Django 博客项目01 数据库设计与验证码校验+Ajax登录
数据库设计
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登录的更多相关文章
- django博客项目8:文章详情页
首页展示的是所有文章的列表,当用户看到感兴趣的文章时,他点击文章的标题或者继续阅读的按钮,应该跳转到文章的详情页面来阅读文章的详细内容.现在让我们来开发博客的详情页面,有了前面的基础,开发流程都是一样 ...
- django博客项目3:创建 Django 博客的数据库模型
设计博客的数据库表结构 博客最主要的功能就是展示我们写的文章,它需要从某个地方获取博客文章数据才能把文章展示出来,通常来说这个地方就是数据库.我们把写好的文章永久地保存在数据库里,当用户访问我们的博客 ...
- Django——博客项目
博客项目 目前的目标是构建一个基于Django的前后端完整的博客系统,首先对项目流程整理如下: 1. 分析需求 1.1. 基于用户认证组件和Ajax实现登录验证 图形验证码核心代码: 模板: < ...
- django博客项目5:博客首页视图(2)
真正的 Django 博客首页视图 在此之前我们已经编写了 Blog 的首页视图,并且配置了 URL 和模板,让 Django 能够正确地处理 HTTP 请求并返回合适的 HTTP 响应.不过我们仅仅 ...
- 9.28 Django博客项目(一)
2018-9-28 17:37:18 今天把博客项目 实现了注册和添加图片的功能! 放在了自己的github上面 源码! https://github.com/TrueNewBee/bbs_demo ...
- django博客项目6:Django Admin 后台发布文章
在此之前我们完成了 Django 博客首页视图的编写,我们希望首页展示发布的博客文章列表,但是它却抱怨:暂时还没有发布的文章!如它所言,我们确实还没有发布任何文章,本节我们将使用 Django 自带的 ...
- django博客项目2.建立 Django 博客应用
建立博客应用 我们已经建立了 Django 博客的项目工程,并且成功地运行了它.不过到目前为止这一切都还只是 Django 为我们创建的项目初始内容,Django 不可能为我们初始化生成博客代码,这些 ...
- django博客项目1.环境搭建
安装 Python Windows 下安装 Python 非常简单,去 Python 官方网站找到 Python 3 的下载地址,根据你的系统选择 32 位或者 64 位的安装包,下载好后双击安装即可 ...
- <Django>博客项目
0.项目的通用流程 项目立项 需求分析 原型 前端 页面设计 UI及交互实现 后端 架构设计 数据库设计 代码模板实现 单元测试 网站整合 功能及集成测试 网站发布 1.BBS项目需求分析 需要哪些表 ...
随机推荐
- POJ 1847 dijstra算法
POJ 无限循环CE中.感觉是读题难.然后就可以建图上模板了. 附个人代码: #include<stdio.h>#include<string.h>#include<io ...
- HDU 2891
DESCRIPTION: 大意是说 先给你n个 同学的 上课时间.一周的第几天,开始和结束的时间点.然后对应q个出去玩的时间.要你给出谁不能出去.如果都能出去就输出none. 开始做的时候觉得每个同学 ...
- 若所有的参数皆需要类型转换——请为此采用non-member函数
若所有的参数皆需要类型转换--请为此采用non-member函数 经常使用C++的程序猿(希望更多的程序媛),一般不会同意让classes支持类型转换,至于为什么,请看后续的博客.假如我们设计一个表示 ...
- LA3905
题意: 给出n颗流星,第i颗在第T秒时飞到(xi+ai*t,yi+bi*t),给出一个矩形,问在某一时刻这个矩形中的流星数目最多有多少 题解: 首先计算出每一颗流星经过时间 然后左端点移动,计算出少了 ...
- tensorflow 模型保存后的加载路径问题
import tensorflow as tf #保存模型 saver = tf.train.Saver() saver.save(sess, "e://code//python//test ...
- 用redis做简单的任务队列(一)
队列本身其实是个有序的列表,而Redis是支持list的,我们可以查看Redis的官方文档 http://redis.io/commands#list,其中我们可以对这个队列的两端分别进行操作,所以其 ...
- sqlserver 2008评估期已过
sqlserver 评估期已过 分类: SQL SERVER2012-08-22 17:04 977人阅读 评论(0) 收藏 举报 打开sqlserver出现提示:评估期已过.有关如何升级的测试版软件 ...
- DevExpress v17.2新版亮点—DevExtreme篇(三)
用户界面套包DevExpress DevExtreme v17.2终于正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExtreme v17.2 的New Color Sche ...
- linux 简单常用命令
kill -3 pid就是发送信号3也就是SIGQUIT给进程pid.kill -9 就是发信号9也就是SIGKILL. pwd: 打印当前工作目录ls:默认显示当前工作目录内容cd:改变当前工作目录 ...
- 《C++ Primer》笔记-inline内联函数
inline 函数避免函数调用的开销 // find longer of two strings const string &shorterString(const string &s ...