BBS项目(一):BBS需求分析 数据表设计 注册登录功能实现
BBS需求分析
# 运营部门,销售部门 =》 业务部门
# 产品经理 => 原型图 => 需求评审:测试人员,产品,开发,前端,后端,主管,技术经理
# 什么时候完成,上线?
# 开发... 提测 => 交给测试人员 => 两轮测试 => dev, test, release, master
# git
1. 用户表(扩展auth_user表)
phone
avatar
create_time
# 一对一站点表
blog = OneToOne
2. 站点表
站点名称
站点标题
站点样式: css代码 => 路径
3. 标签表
标题
# 一对多站点表
4. 分类表
分类名称 # 无限级分类
# 一对多站点表
5. 文章表
标题
简介
内容
create_time
# 一对多站点表
blog = ForeignKey
# 多对多标签表
tags = manytomany
# 一对多分类表
cate = ForeignKey
'''优化字段'''
up_num # 点赞数
down_num # 点踩数
comment_num # 评论数
6. 点赞点踩表
# 哪个用户点赞了还是点踩了那篇文章
user
article
is_up 0/1
7. 评论表comment
user
article
content
create_time
pid = ForeignKey(to='comment') # 自关联外键
pid = ForeignKey(to='self')
'''
根评论和子评论
1. 哥很帅
1.1 确实很帅
1.2 男神
'''
id user article content pid(parent_id)
1 1 1 aa 0
2 2 1 bb 1
3 3 1 cc 1
数据表设计
from django.db import models
from django.contrib.auth.models import AbstractUser
# 1. 用户表
class UserInfo(AbstractUser):
phone = models.CharField(max_length=32, verbose_name='手机号')
# 头像
avatar = models.FileField(upload_to='static/img', default='static/img/default.png')
# 创建时间
create_time = models.DateTimeField(auto_now_add=True)
# 2. 站点表
class Blog(models.Model):
site_name = models.CharField(max_length=64, verbose_name='站点名称')
site_title = models.CharField(max_length=64, verbose_name='站点标题')
site_style = models.CharField(max_length=64, verbose_name='站点样式')
# 3. 标签表
class Tag(models.Model):
title = models.CharField(max_length=64, verbose_name='标签名称')
# 4. 分类表
class Category(models.Model):
title = models.CharField(max_length=64, verbose_name='分类名称')
# 5. 文章表
class Article(models.Model):
title = models.CharField(max_length=128, verbose_name='文章标题')
desc = models.CharField(max_length=512, verbose_name='文章简介')
content = models.TextField(verbose_name='文章内容')
create_time = models.DateTimeField(auto_now_add=True)
# 外键关系
blog = models.ForeignKey(to='Blog', on_delete=models.CASCADE)
category = models.ForeignKey(to='Category', on_delete=models.CASCADE)
# 多对多
tags = models.ManyToManyField(to='Tag',
through='Article2Tag',
through_fields=('article', 'tag')
)
# 优化字段
up_num = models.IntegerField(verbose_name='点赞数')
down_num = models.IntegerField(verbose_name='点踩数')
comment_num = models.IntegerField(verbose_name='评论数')
class Article2Tag(models.Model):
article = models.ForeignKey(to='Article', on_delete=models.CASCADE)
tag = models.ForeignKey(to='Tag', on_delete=models.CASCADE)
# 6. 点赞点踩表
class UpAndDown(models.Model):
user = models.ForeignKey(to='UserInfo', on_delete=models.CASCADE)
article = models.ForeignKey(to='Article', on_delete=models.CASCADE)
# 布尔值, True/False => 1/0
is_up = models.BooleanField()
# 7. 评论表
class Comment(models.Model):
user = models.ForeignKey(to='UserInfo', on_delete=models.CASCADE)
article = models.ForeignKey(to='Article', on_delete=models.CASCADE)
content = models.CharField(max_length=512, verbose_name='评论内容')
create_time = models.DateTimeField(auto_now_add=True)
# parent_id = models.ForeignKey(to='Comment')
parent = models.ForeignKey(to='self', on_delete=models.CASCADE)
注册页面前端
前端页面:
用户名、密码、确认密码、邮箱、上传头像
提交按钮:
上传头像
示例:
将img放在label标签内,点击图片即可触发上传文件。
使用display:none
将上传文件的input标签隐藏。
用户头像展示:
点击label标签触发的不是click事件,而是change事件。
思路1:文件阅读器
由于readAsDataURL
是异步操作,所以我们交给文件阅读器的图片还没读完,就执行下一行代码,attr
修改标签的src属性为图片数据,所以此时图片不显示。我们希望把异步操作变成同步操作,等待文件阅读器读取完再执行下一行代码。
添加onload事件,等待文件阅读器读取完再执行:
注意:文件阅读器是临时读取,并没有把用户头像上传至后台。(不消耗后端资源)
提交数据 FormData
给按钮绑定点击事件。借助于FormData()
:
验证数据和追加数据:
追加数据:把获取到的数据放入FormData对象中。
提交ajax:
两行参数:
注意:这两个参数不加ajax请求都没有反应。第二需要把crsf校验给关了。
前端校验layer框:
注意这个layer框需要引入layer前端组件:
注意:layer前端组件需要Jquery的支持。
下载地址:https://layui.gitee.io/v2/docs/
效果:
注册后端逻辑
forms组件尽量不要用,封装好的功能出了故障不好排查。
接受参数
给前端返回的json数据:
导入JsonResponse。
验证参数
后端发现没有用户名时,修改给前端返回的json数据的键值对。修改状态码为1000起步。用JsonResponse返回给前端。
业务状态码:标识某一个错误信息
响应状态码:200响应成功 404找不到文件
示例:
由前缀和业务码组成:
10表示财务相关、20表示用户相关、30表示订单相关。
验证两次密码输入是否一致:
邮箱格式验证:
处理正常的业务逻辑:
将获取的前端数据存放于数据字典中。
验证用户名是否存在:
数据入库
双星号解包字典,变成关键字实参传入create方法。
这里如果业务复杂还需要加事务操作,利用事务原子性,保证数据不会出现添加一半的情况。
还有一个问题,就是使用create方法数据入库时,密码还是明文的,需要处理密码:
如果使用create_user则无法控制加密的方式,也不知道django是怎么加密的。读取的时候,也需要使用auth模块去比对密码。建议:不要使用auth模块,不太方便。
密码加盐操作
导入from django.core import settings
使用的是配置文件中的固定盐:
这个盐也可以自己修改。
返回数据
前端页面ajax回调函数:
如果后端返回的状态码为200,则跳转到登录页面。其他情况则弹出提示信息。通过给location.href
赋值,跳转到login页面。
登录页面前端
生成验证码
效果:
验证码前端示例:
随机验证码生成:
到网上下载代码。也可以引入ttf字体文件(修改字体样式)。
安装pillow模块:
导入from PIL import Image,ImageDraw, ImageFont
代码示例:
字体下载:
参数含义:
get_random
:生成随机数
img_font
:使用我们导入的字体
tmp
:随机生成的一个字符
(i * 60 + 60,-2)
:两个验证码字母之间的距离
存储到session:
开启路由接口:
修改前端页面:
这里的Img标签就可以显示get_code视图函数用Httpresponse返回的验证码图片。
效果:
前端提交数据
前端按钮绑定点击事件:
前端验证:
提交ajax请求:
登录成功之后跳转到首页:
登录后端逻辑
接受参数
验证参数
验证验证码是否正确:
cookies session除了可以记录用户信息,也可以记录验证码信息。之前我们生成的验证码保存在了session表,现在我们拿出来进行比对。
验证码应该是不区分大小写的:
验证用户是否存在:
登录逻辑
获取用户输入的密码,此时密码是明文,需要加密之后再比对:
不要这样写两个校验(不要提供多余的信息,防范恶意破解密码):
不要告知用户到底是用户名不存在,还是用户名与密码匹配不上。
写一个校验就行了:
(企业中的登录不是这么简单,示例:一个登录功能3000行代码)
session表记录用户信息:
id是用户对象在session表中的id值。
session表中数据的过期时间到了之后也不会立即删除。
封装加密函数
加密函数:
使用函数: