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)

注册页面前端

前端页面:
用户名、密码、确认密码、邮箱、上传头像

image-20221227185723279

提交按钮:

image-20221228132343065

上传头像

image-20221228132706200
示例:
image-20221228132907869

将img放在label标签内,点击图片即可触发上传文件。
使用display:none将上传文件的input标签隐藏。

用户头像展示:
点击label标签触发的不是click事件,而是change事件。
思路1:文件阅读器
image-20221228134549921

由于readAsDataURL是异步操作,所以我们交给文件阅读器的图片还没读完,就执行下一行代码,attr修改标签的src属性为图片数据,所以此时图片不显示。我们希望把异步操作变成同步操作,等待文件阅读器读取完再执行下一行代码。

添加onload事件,等待文件阅读器读取完再执行:
image-20221228135633452

注意:文件阅读器是临时读取,并没有把用户头像上传至后台。(不消耗后端资源)

提交数据 FormData

给按钮绑定点击事件。借助于FormData():
image-20221228140623671

验证数据和追加数据:
image-20221228140731283

追加数据:把获取到的数据放入FormData对象中。

提交ajax:

image-20221228140929770

两行参数:
image-20221228153012903

注意:这两个参数不加ajax请求都没有反应。第二需要把crsf校验给关了。

前端校验layer框:
注意这个layer框需要引入layer前端组件:
注意:layer前端组件需要Jquery的支持。

image-20221228173310115

下载地址:https://layui.gitee.io/v2/docs/

image-20221228142950910

效果:
image-20221228143008975

注册后端逻辑

forms组件尽量不要用,封装好的功能出了故障不好排查。

接受参数

image-20221228143433778

给前端返回的json数据:
导入JsonResponse。

image-20221228150044409

验证参数

image-20221228150316617

后端发现没有用户名时,修改给前端返回的json数据的键值对。修改状态码为1000起步。用JsonResponse返回给前端。

业务状态码:标识某一个错误信息
响应状态码:200响应成功 404找不到文件

示例:

image-20221228150858908

由前缀和业务码组成:
10表示财务相关、20表示用户相关、30表示订单相关。

验证两次密码输入是否一致:

image-20221228151111212

邮箱格式验证:

image-20221228151340437

处理正常的业务逻辑:

image-20221228151522358

将获取的前端数据存放于数据字典中。

验证用户名是否存在:
image-20221228161433085

数据入库

image-20221228151720009

双星号解包字典,变成关键字实参传入create方法。
这里如果业务复杂还需要加事务操作,利用事务原子性,保证数据不会出现添加一半的情况。

还有一个问题,就是使用create方法数据入库时,密码还是明文的,需要处理密码:
image-20221228152336099

如果使用create_user则无法控制加密的方式,也不知道django是怎么加密的。读取的时候,也需要使用auth模块去比对密码。建议:不要使用auth模块,不太方便。

密码加盐操作

导入from django.core import settings
image-20221228152449259

使用的是配置文件中的固定盐:

image-20221228152523514

这个盐也可以自己修改。

返回数据

image-20221228160109743

前端页面ajax回调函数:
image-20221228160222728

如果后端返回的状态码为200,则跳转到登录页面。其他情况则弹出提示信息。通过给location.href赋值,跳转到login页面。

登录页面前端

生成验证码

效果:

image-20221228162015572

验证码前端示例:
image-20221228162547842

随机验证码生成:
到网上下载代码。也可以引入ttf字体文件(修改字体样式)。

安装pillow模块:

导入from PIL import Image,ImageDraw, ImageFont
image-20221228163607878

代码示例:
image-20221228163723013

字体下载:
image-20221228164014686

参数含义:
image-20221228164127372

get_random:生成随机数
img_font:使用我们导入的字体
tmp:随机生成的一个字符
(i * 60 + 60,-2):两个验证码字母之间的距离

存储到session:
image-20221228164846094

开启路由接口:

image-20221228165059977

修改前端页面:
image-20221228164752368

这里的Img标签就可以显示get_code视图函数用Httpresponse返回的验证码图片。

效果:
image-20221228165305439

前端提交数据

前端按钮绑定点击事件:

image-20221228165803486

前端验证:
image-20221228165842798

提交ajax请求:

image-20221228170153266

登录成功之后跳转到首页:

image-20221228170402860

登录后端逻辑

接受参数

image-20221228170557344

验证参数

验证验证码是否正确:
image-20221228170814281

cookies session除了可以记录用户信息,也可以记录验证码信息。之前我们生成的验证码保存在了session表,现在我们拿出来进行比对。

验证码应该是不区分大小写的:

image-20221228173105442

验证用户是否存在:

image-20221228170904975

登录逻辑

获取用户输入的密码,此时密码是明文,需要加密之后再比对:

image-20221228171146960

不要这样写两个校验(不要提供多余的信息,防范恶意破解密码):
不要告知用户到底是用户名不存在,还是用户名与密码匹配不上。
image-20221228171703290

写一个校验就行了:

image-20221228171915993

(企业中的登录不是这么简单,示例:一个登录功能3000行代码)

session表记录用户信息:
image-20221228172257018

id是用户对象在session表中的id值。
session表中数据的过期时间到了之后也不会立即删除。

封装加密函数

加密函数:

image-20221228174350815

使用函数:

image-20221228174512200
posted @ 2022-12-28 17:54  passion2021  阅读(69)  评论(0编辑  收藏  举报