BBS项目
BBS项目表设计及关联
1.要开发的功能
-注册功能
-首页:文章展示,导航栏,用户中心,广告位
-个人主页:文章展示,侧边栏过滤(分类、标签、数据)
-文章详情:点赞点踩,评论(父评论、子评论)
-后台管理:个人文章展示(增加、删除、修改文章)
-发布文章:富文本编辑器(编辑文章内容的地方),xss攻击处理
'技术选型:python3.8、django2.2.2、mysql5.6、jquery2.x、bootstrap@3'
2.设计数据库(bbs)
-用户表(基于auth的user表扩写,扩写字段)
-博客表(跟用户表一对一)
-标签表(按标签过滤筛选)
-分类表(按分类过滤筛选)
-文章表(文章内容、新增、删除)
-点赞点踩表(给文章点赞点踩)
-评论表(给文章评论或给评论评论)
3.表的关联关系
-用户表(基于auth的user表扩写,扩写字段)
-博客表:跟用户表一对一
-标签表:跟博客表一对多,跟文章是多对多
-分类表:跟博客表一对多,跟文章是一对多
-文章表:跟博客表是一对多
-点赞点踩表:跟用户一对多,跟文章表一对多
-评论表:跟用户一对多,跟文章表一对多

项目表字段编写和表迁移
1.配置文件
-'DIRS': [os.path.join(BASE_DIR, 'templates')]
-DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'bbs',
'HOST': '127.0.0.1',
'PORT': 3306,
'USER': 'root',
'PASSWORD': '321',
}
}
2.国际化
LANGUAGE_CODE = 'zh-hans' # 语言中文
TIME_ZONE = 'Asia/Shanghai' # 使用上海时区
USE_I18N = True
USE_L10N = True
USE_TZ = False # 是否使用TIME_ZONE的时间
写表模型
from django.db import models
from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
'用户表'
# username,password,email...
phone = models.CharField(max_length=32, null=True)
# 存文件字段(头像)
avatar = models.FileField(upload_to='avatar', default='avatar/default.png')
# 一对一关联了blog表
blog = models.OneToOneField(to='Blog', on_delete=models.CASCADE)
class Blog(models.Model):
'博客表'
title = models.CharField(max_length=32, mull=True, verbose_name='主标题')
# verbose_name相当于注释
site = models.CharField(max_length=32, mull=True, verbose_name='副标题')
site_style = models.CharField(max_length=32, mull=True, verbose_name='个人站点样式')
class Tag(models.Model):
'标签表'
name = models.CharField(max_length=32, verbose_name='标签名字')
blog = models.ForeignKey(to='Blog', on_delete=models.CASCADE)
class Category(models.Model):
'分类表'
name = models.CharField(max_length=32, verbose_name='分类名字')
blog = models.ForeignKey(to='Blog', on_delete=models.CASCADE)
class Article(models.Model):
'文章表'
title = models.CharField(max_length=32, verbose_name='文章名字')
desc = models.CharField(max_length=255, verbose_name='文章摘要')
content = models.TextField(verbose_name='文章内容')
# auto_now_add=True新增文章这个字段可以不传,自动把当前时间加上
create_time = models.DateTimeField(auto_now_add=True, verbose_name='文章创建时间')
blog = models.ForeignKey(to='Blog', on_delete=models.CASCADE)
category = models.ForeignKey(to='Category', on_delete=models.CASCADE)
# 多对多关系,需要创建第三张表
tag = models.ManyToManyField(to='Tag')
class UpAndDown(models.Model):
'点赞点踩表'
user = models.ForeignKey(to='UserInfo', on_delete=models.CASCADE)
article = models.ForeignKey(to='Article', on_delete=models.CASCADE)
# True就是点赞,False就是点踩
is_up = models.BooleanField(verbose_name='点赞或点踩')
create_time = models.DateTimeField(auto_now_add=True)
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=64, verbose_name='评论的内容')
creat_time = models.DateTimeField(auto_now_add=True)
# 评论的评论,外键只能是该表中的id
parent = models.ForeignKey(to='self', on_delete=models.CASCADE, null=True)
1.安装pymysql:pip3 install pymysql
import pymysql
pymysql.install_as_MySQLdb()
"在django2.0.7及以后版本,需要改源码才能使用:operations.py---》146行,改成query = query.encode(errors='replace')"
2.不想该源码加配置,可以直接使用mysqlclient:pip3 install mysqlclient
下载好后就可以了
创建项目
1.配置文件
-'DIRS': [os.path.join(BASE_DIR , 'templates')]
-国际化
LANGUAGE_CODE = 'zh-hans' # 语言中文
TIME_ZONE = 'Asia/Shanghai' # 使用上海时区
USE_I18N = True
USE_L10N = True
USE_TZ = False
-使用MySQL数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'bbs',
'HOST': '127.0.0.1',
'PORT': 3306,
'USER': 'root',
'PASSWORD': '321',
}
}
-注册页面搭建
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
# 头像上传路径
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
AUTH_USER_MODEL = 'blog.UserInfo'
上传的图片要开启media的访问,才能看到图片
-配置文件
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
-路由中
from BBS import settings
from django.views.static import serve
path('media/<path:path>', serve, {'document_root': settings.MEDIA_ROOT}),
处理xss攻击
1.xss攻击:跨站脚本攻击
在内容中存储了script的脚本,前端渲染的时候,使用了safe,渲染html内容,导致如果存在script脚本,脚本就会执行,所以在存储的时候,就要把恶意脚本删除
from bs4 import BeautifulSoup
# 第一个参数是html内容,第二个参数是解析器
soup = BeautifulSoup(content, 'html.parser')
# 把html的内容截取出来,只截取70个文字
desc = soup.text.replace('/n', '').replace('/r', '')[:70] + '...'
# 获取html中所有的script标签
script_list = soup.findAll('script')
# 把获取到的script标签删除
for script in script_list:
script.decompose()
退出登录
from django.contrib.auth import logout as out
def logout(request):
# 删除session和cookie
out(request)
return redirect('/')
django发送邮件
1.python 代码就可以发送邮件 smtplib 内置模块,可以发送邮件
2.你要发邮件要有个发件箱:就是你的邮箱(qq邮箱,163邮箱。。。)
-配置我们的邮箱,让它可以用python代码发送邮件
-以qq邮箱为例:开启smtp服务:IMAP/SMTP服务
fjkmdxelrgfzbgae
3.django发送右键---》本质是封装了 smtplib 内置模块
-再django中
from django.core.mail import send_mail
res1 = send_mail('邮件标题', '邮件内容', settings.EMAIL_HOST_USER, ["2247675450@qq.com"])
随机验证码
import random
from PIL import Image, ImageDraw, ImageFont
def get_rgb():
# 将图片文字设置为随机色
return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
def get_code(request):
'''
rgb:ren(红),green(绿),blue(蓝)
三原色的色值:0-255
'''
# 创建图片
img = Image.new('RGB', (500, 40), (255, 255, 255))
# 创建一个字体对象,设置字体大小
font = ImageFont.truetype('./static/font/xx.ttf', 30)
# 在图片上写字
img_draw = ImageDraw.Draw(img)
for i in range(4):
# 从0-9随机一个数字
num = random.randint(0, 9)
# 从a-z随机一个字母
upper = chr(random.randint(65, 90))
# 从A-Z随机一个字母
low = chr(random.randint(97, 122))
# python 是强类型语言,不同类型直接不能直接相加,随机选一个转换为字符串
ran = str(random.choice([num, upper, low]))
# 加到空字符串
code_str += ran
# 选用font内的字体,字符y轴每个字符之间间隔60,将文字设置为随机色
img_draw.text((70 + i * 110, 0), ran, fill=get_rgb(), font=font)
print(code_str)
# 将正确的验证码存到session里面,之后验证验证码是就可以直接从session中取出
request.session['code'] = code_str
# 在图片上画点、线
width = 450
height = 30
for i in range(10):
# 随机线的起始点终点的x轴y轴
x1 = random.randint(0, width)
x2 = random.randint(0, width)
y1 = random.randint(0, height)
y2 = random.randint(0, height)
# 在图片上画线
img_draw.line((x1, y1, x2, y2), fill=get_rgb())
for i in range(50):
# 画点,随机点的x轴y轴
img_draw.point([random.randint(0, width), random.randint(0, height)], fill=get_rgb())
# 保存到内存
byte_io = BytesIO()
# 指定图片格式
img.save(byte_io, 'png')
# 从BytesIO取出二进制,返回给前端
return HttpResponse(byte_io.getvalue())
事务
from django.db import transaction
# 使用事务,保证内的行动,要么都成功,要么都失败
with transaction.atomic():