BBS版本一
day15 BBS项目
项目开发流程
- 需求分析
- 项目设计
- 分组开发
- 测试
- 上线
表设计
'''
一个项目中最重要的不是业务逻辑的书写
而是前期的表设计,只要将表设计好了,后续的功能书写才会一帆风顺
'''
# bbs表设计
1.用户表
继承AbstractUser
扩展字段:
phone :电话号码
avatar :用户头像
create_time :创建时间
外键字段:
一对一个人站点表
2.个人站点表
site_name:站点名称
site_title;站点标题
site_theme:站点样式
外键字段:
一对多个人站点
3.文章标签表
name:标签名
外键字段:
一对多个人站点
4.文章分类表
name:分类名
外键字段:
一对多个人站点
5.文章表
title:文章标题
desc:文章简介
content:文章内容
create_time:发布时间
# 数据库字段设计优化(虽然下面的三个字段可以从其他表里面跨表查询计算得出,但是频繁跨表效率比较低下)
'''所以在文章表添加下面的三个字段,添加普通字段同步更新,减少跨表查询次数'''
up_num :点赞数
down_num :点踩数
comment_num :评论数
外键字段:
一对多个人站点
多对多文章标签
一对多文章分类
6.点赞点踩表
记录哪个用户给哪篇文章点了赞还是点了踩
user :用户 ForeignKey(to="User")
article :文章 ForeignKey(to="Article")
is_up :是否点赞 BooleanField()
7.文章评论表
记录哪个用哪个户给哪篇文章写了哪些评论内容
user ForeignKey(to="User")
article ForeignKey(to="Article")
content CharField()
comment_time DateField()
parent ForeignKey(to="Comment",null=True) # 自关联
# parent ForeignKey(to="self",null=True) # orm提供的语法自关联
评论分为根评论和子评论(可以评论别人评论的)
根评论:是评论文章内容的评论
字评论:是回复别人的评论
# 外键关系:是一对多的
创建表字段
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
# 用户表
class UserInfo(AbstractUser):
phone = models.CharField(max_length=32, verbose_name='手机号')
# 头像
avatar = models.FileField(upload_to='static/img', default='static/img/111.png', verbose_name='头像')
'''
给avatar字段传文件对象,该文件会自动存储到avatar文件下,然后avatar字段只保存文件路径
'''
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
# 一对一站点表:用户表和站点表是一对一关系
blog = models.OneToOneField(to='Blog', null=True, verbose_name='关联站点表')
# 站点表
class Blog(models.Model):
site_name = models.CharField(max_length=64, verbose_name='站点名称')
site_title = models.CharField(max_length=64, verbose_name='站点标题')
site_theme = models.CharField(max_length=64, verbose_name='站点主题')
# 标签表
class Tag(models.Model):
name = models.CharField(max_length=32)
# 一对多站点表:标签表和站点表是一对多关系
blog = models.ForeignKey(to='Blog', verbose_name='关联站点表')
# 分类表
class Category(models.Model):
name = models.CharField(max_length=32, verbose_name='分类名称')
# 一对多站点表:分类表和站点表是一对多关系
blog = models.ForeignKey(to='Blog', verbose_name='关联站点表')
# 文章表
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, verbose_name='创建时间')
# 优化字段
up_num = models.IntegerField(verbose_name='点赞数')
down_num = models.IntegerField(verbose_name='点踩数')
comment_num = models.IntegerField(verbose_name='评论数')
# 外键关系
# 一对多站点表:文章表和站点表是一对多关系
blog = models.ForeignKey(to='Blog', verbose_name='关联站点表')
tags = models.ManyToManyField(to='Tag', through='Article2Tag',
through_fields=('article', 'tag'),
verbose_name='关联第三张表'
)
category = models.ForeignKey(to='Category', verbose_name='关联分类表')
# 自己创建的第三张表,用于扩建字段
class Article2Tag(models.Model):
article = models.ForeignKey(to='Article')
tag = models.ForeignKey(to='Tag')
# 点赞点踩表
class UpAndDown(models.Model):
user = models.ForeignKey(to='UserInfo', verbose_name='关联用户表')
article = models.ForeignKey(to='Article', verbose_name='关联文章表')
is_up = models.BooleanField() # 存的是0/1
# 评论表
class Comment(models.Model):
user = models.ForeignKey(to='UserInfo', verbose_name='关联用户表')
article = models.ForeignKey(to='Article', verbose_name='关联文章表')
content = models.CharField(max_length=512, verbose_name='评论内容')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
# 根评论和子评论一对多的关系,自关联
parent_id = models.ForeignKey(to='self', null=True) # self就是关联自己表
搭建注册页面
Title
{% load static %}
注册页面
'''
其中包换头像上传功能
'''
注册功能实现
from django.shortcuts import render, HttpResponse, redirect
from django.http import JsonResponse
from app01 import models
def register(request):
if request.method == 'POST':
# 1.获取用户数据
back_dic = {'code': 200, 'msg': '注册成功'}
username = request.POST.get('username')
pwd = request.POST.get('pwd')
re_pwd = request.POST.get('re_pwd')
email = request.POST.get('email')
avatar = request.FILES.get('myfile')
# 2.验证参数
if not username:
back_dic['code'] = 201
back_dic['msg'] = '用户名必须填写'
return JsonResponse(back_dic)
if not pwd:
back_dic['code'] = 202
back_dic['msg'] = '密码必须填写'
return JsonResponse(back_dic)
if not re_pwd:
back_dic['code'] = 203
back_dic['msg'] = '确认密码必须填写'
return JsonResponse(back_dic)
if not email:
back_dic['code'] = 204
back_dic['msg'] = '邮箱必须填写'
return JsonResponse(back_dic)
res = models.UserInfo.objects.filter(username=username).first()
email_obj = models.UserInfo.objects.filter(email=email).first()
# 判断用户是否存在
if res:
back_dic['code'] = 205
back_dic['msg'] = '用户名已存在'
return JsonResponse(back_dic)
# 判断密码是否一致
if not pwd == re_pwd:
back_dic['code'] = 206
back_dic['msg'] = '密码两次不一致'
return JsonResponse(back_dic)
# 判断邮箱是否已经绑定
if email_obj:
back_dic['code'] = 207
back_dic['msg'] = '邮箱已绑定'
return JsonResponse(back_dic)
# 3.业务逻辑
data_dic = {}
if avatar:
data_dic['avatar'] = avatar
# 给密码加密
import hashlib
m = hashlib.md5()
m.update(pwd.encode('utf-8'))
pwd = m.hexdigest()
data_dic['username'] = username
data_dic['password'] = pwd
data_dic['email'] = email
# 4.存入数据库
models.UserInfo.objects.create(**data_dic) # 利用可变长参数,传入数据
# 5.返回格式化数据
back_dic['url'] = '/login/'
return JsonResponse(back_dic)
return render(request, 'register.html')
登录页面搭建
Title
{% load static %}
登录页面
登录功能实现
def login(request):
if request.method == 'POST':
back_dic = {'code': 200, 'msg': '登录成功'}
# 接收参数
username = request.POST.get('username')
password = request.POST.get('password')
code = request.POST.get('code')
# 验证参数
if not code:
back_dic['code'] = 208
back_dic['msg'] = '验证码必须填写'
return JsonResponse(back_dic)
if request.session.get('code').upper() != code.upper():
back_dic['code'] = 209
back_dic['msg'] = '验证码填写错误'
return JsonResponse(back_dic)
# 业务逻辑
# 给密码加密
import hashlib
m = hashlib.md5()
m.update(password.encode('utf-8'))
password = m.hexdigest()
user_obj = models.UserInfo.objects.filter(username=username, password=password).first()
if not user_obj:
back_dic['code'] = 210
back_dic['msg'] = '用户名或者密码错误'
return JsonResponse(back_dic)
# 保存用户信息
request.session['id'] = user_obj.id
request.session['username'] = user_obj.username
# 返回数据
back_dic['url'] = '/home/'
return JsonResponse(back_dic)
return render(request, 'login.html')
验证码功能
def get_code(request):
# 最终步骤4:写图片验证码
img_obj = Image.new('RGB', (430, 35), get_random())
img_draw = ImageDraw.Draw(img_obj) # 产生一个画笔对象
img_font = ImageFont.truetype('static/font/包图小白体.ttf', 30) # 字体样式 大小
# 随机验证码 五位数的随机验证码 数字 小写字母 大写字母
code = ''
for i in range(4):
random_upper = chr(random.randint(65, 90))
random_lower = chr(random.randint(97, 122))
random_int = str(random.randint(0, 9))
# 从上面三个里面随机选择一个
tmp = random.choice([random_lower, random_upper, random_int])
# 将产生的随机字符串写入到图片上
"""
为什么一个个写而不是生成好了之后再写
因为一个个写能够控制每个字体的间隙 而生成好之后再写的话
间隙就没法控制了
"""
img_draw.text((i * 60 + 60, -2), tmp, get_random(), img_font)
# 拼接随机字符串
code += tmp
print(code)
# 随机验证码在登陆的视图函数里面需要用到 要比对 所以要找地方存起来并且其他视图函数也能拿到
request.session['code'] = code
io_obj = BytesIO()
img_obj.save(io_obj, 'png')
return HttpResponse(io_obj.getvalue())
搭建首页项目
Title
{% load static %}
Panel content
Panel content
Panel content
{% for article_obj in article_list %}
{{ article_obj.title }}
{{ article_obj.desc }}
{{ article_obj.blog.userinfo.username }}
{{ article_obj.create_time| date:'Y-m-d H:i:s' }}
({{ article_obj.up_num }})
({{ article_obj.down_num }})
({{ article_obj.comment_num }})
{% endfor %}
Panel content
Panel content
Panel content
首页
def home(request):
article_list = models.Article.objects.all()
return render(request, 'home.html', locals())
修改密码功能
def get_md5(pwd):
import hashlib
m = hashlib.md5()
m.update(pwd.encode('utf-8'))
return m.hexdigest()
def set_password(request):
if request.method == 'POST':
back_dic = {'code': 200, 'msg': '修改密码成功'}
# 获取数据
old_password = request.POST.get('old_password')
new_password = request.POST.get('new_password')
re_password = request.POST.get('re_password')
# 验证参数
old_password = get_md5(old_password)
user_obj = models.UserInfo.objects.filter(username=request.session.get('username'),
password=old_password).first()
if not user_obj:
back_dic['code'] = 211
back_dic['msg'] = '原密码错误'
return JsonResponse(back_dic)
if new_password != re_password:
back_dic['code'] = 212
back_dic['msg'] = '两次密码不一致'
return JsonResponse(back_dic)
# 业务逻辑
new_password = get_md5(new_password)
# 修改数据
models.UserInfo.objects.filter(pk=request.session.get('id')).update(password=new_password)
return JsonResponse(back_dic)
退出登录功能
def logout(request):
request.session.flush()
return redirect('/home/')
个人站点搭建页面
Title
{% load static %}
Panel heading
...
Panel heading
...
Panel heading
...
{% for article_obj in article_list %}
{{ article_obj.title }}
{{ article_obj.desc }}
posted @
{{ article_obj.create_time| date:'Y-m-d H:i:s' }}
{{ article_obj.blog.userinfo.username }}
点赞({{ article_obj.up_num }})
点踩({{ article_obj.down_num }})
评论({{ article_obj.comment_num }})
{% endfor %}
个人站点实现
def site(request, username):
# 验证站点名称是否存在
user_obj = models.UserInfo.objects.filter(username=username).first()
if not user_obj:
return render(request, '404.html')
# 查询当前站点的所有文章
blog = user_obj.blog
article_list = models.Article.objects.filter(blog=blog).all()
return render(request, 'site.html', locals())