一、BBS-个人博客项目完整搭建
项目开发流程
一、项目分类
现在互联网公司需要开发的主流web项目一般分为两类:面向互联网用户,和公司内部管理。
面向互联网用户: C( consumer) 端项目
公司内部管理:B( business) 端项目
还有一类web应用,基本采用基于角色的权限控制,不同的员工在这套系统中拥有不同的权限,
适用于公司内部管理。
基于权限的后台关系系统:
RBAC权限管理系统
二、项目开发模式分类
最常见的两类为瀑布开发模式和敏捷开发模式。
1 、瀑布开发模式
瀑布开发模式是一种更倾向于严格控制的管理模式,要求在提出需求之后,充分完成项目的规划,各阶段都要经过严格的评审,只有当一个阶段的需求完成得非常好时才能进入下一个阶段。
但是瀑布开发模式开发的失败率较高,且周期较长,于是就产生了敏捷开发模式。
2 、敏捷开发模式
敏捷开发模式的核心是迭代开发,它将一个项目完整的开发流程分为了几个周期(也可以说是版本),由于每个版本的开发流程相似,看上去相当于一个重复迭代的过程。这么开发的好处是,使一个大的项目能在较短时间内上线,并在后续对它进行不断地迭代和优化。
3 、项目开发流程
- 立项
- 需求分析
- 原型图( 产品画的)
- 切图
- 技术选型,数据库架构设计
- 前后端协同开发
- 上线测试服务器联调
- 测试
- 修改bug
- 上线运行
二、BBS多人博客项目基本功能和需求
比如:产品需求的确定,技术选型,数据库设计. . .
"""
1. 用户表(你可以自己创建,也可以使用auth_user表)
扩展auth_user表
phone
avatar:用来存储头像的地址
create_time:用户注册的时间
...
blog_id = OneToOneField(to='blog')
2. 站点表(blog)
站点名称
站点标题
站点样式:存的是css的路径
3. 分类表(cate)
分类名称
blog = ForeignKey(to='blog')
4. 标签表
标签名称
blog = ForeignKey(to='blog')
5. 文章表(*******************article)
文章标题
文章摘要
文章内容
文章发表时间
# 1. 通过文章id去点赞表或者评论表中查询
# 优化
# 2. 在文章表中增加子弹
up_num 1
down_num 1
comment_num 4
# 外键关系子弹
cate = ForeignKey(to='cate')
tag = ManyToManyField(to='tag')
blog = ForeignKey(to='blog')
6. 点赞点踩表
谁给哪篇文章什么时间点了赞还是踩
user ForeignKey(to='user')
article ForeignKey(to='article')
is_up 0/1
create_time
id user_id article_id is_up create_time
1 1 1 0 ‘’
2 2 1 1 ‘’
7. 评论表(comment)
谁给哪篇文章在什么时间评论了什么内容
user ForeignKey(to='user')
article ForeignKey(to='article')
content
create_time
parent_id ForeignKey(to='comment')
parent_id ForeignKey(to='self')
#自关联
id user_id article_id content create_time parent_id
1 1 1 0 ‘’ 0
2 2 1 1 ‘’ 1
3 2 1 1 ‘’ 2
子评论!!!
评论评论的评论!!!
根评论
1. Python是世界上最好的语言
1.1 PHP是世界上最好的语言
1.2 Java是世界上最好的语言
无限极分类
category表
id cate_name pid
1 手机/数码 0
2 电脑/办公 0
...
20 手机通讯 1
21 运营商 1
...
50 5G手机 20
51 手机 20
...
100 128G/5G 50
"""
三、项目程序设计
四、BBS数据库表结构设计
1.用户表:UserInfo
(通过继承AbstractUser类来扩写Auth_user)
•phone:用户的联系方式
•bg_img: 用户的主页背景
•province: 用户的省份
•city: 用户的城市
•gender : 用户的性别
•avatar:用户的头像
•blog:用户的博客站点(外键一对一关联博客表Blog)
2.博客表:Blog
•title:博客标题
•subtitle: 博客子标题
•style:博客样式
3.文章表:Article
•title:文章标题
•head_img: 头像
•description:文章摘要
•content:文章内容
•create_time:文章的创建时间
•modify_time: 文章的修改时间
•up_num : 点赞数
•down_num: 点踩数
•comment_num: 评论数
•blog:属于哪个博客站点(外键关联博客表Blog)
•category:属于哪个分类(外键关联分类表Category)
4.标签表:Tag
•name:标签名
•blog:属于哪个博客站点(外键关联博客表Blog)
5.分类表:Category
•name:分类名
•blog:属于哪个博客站点(外键关联博客表Blog)
6.评论表:Comment
•user:评论的用户(外键关联用户表UserInfo)
•article:该评论属于哪篇文章(外键关联文章表Article)
•content:评论内容
•comment_time: 评论的创建时间
•comment_id:评论的目标id (外键进行自关联)
7.点赞点踩表:UpAndDown
•user:来自哪个用户(外键关联用户表UserInfo)
•article:属于哪篇文章(外键关联文章表Article)
•is_up:点赞还是点踩(根据bool 值来判断)
•create_time : 点赞或踩的时间
8.文章标签表: Tag2Article
根据文章与标签的多对多关系手动建立的第三张表
• tag:标签名(外键关联标签表Tag)
• article:属于哪篇文章(外键关联文章表Article)
9.轮播图表 Swiper (拓展)
• image: 轮播图图片名
• title:轮播图标题
• img_url: 点击轮播图要跳转的url地址
10.日志表: Log(拓展)
• id : 日志id
• ip: 访问的ip地址
• time: 访问的时间
• url: 访问的url
• device: 访问的浏览器
• platform: 访问的操作系统类型
11.日志表: Log(拓展)
• id : 日志id
• ip: 访问的ip地址
• time: 访问的时间
• url: 访问的url
• device: 访问的浏览器
• platform: 访问的操作系统类型
五、创建BBS表模型
模型层models.py中写入以下orm语句模型来创建表模型
from django. contrib. auth. models import AbstractUser
from django. utils. html import mark_safe
from django. db import models
from markdown import markdown
class Log ( models. Model) :
id = models. AutoField( primary_key= True )
ip = models. CharField( max_length= 64 , verbose_name= '访问IP' , help_text= '访问用户的IP地址' )
time = models. DateTimeField( auto_now_add= True , verbose_name= '访问时间' , help_text= '该用户的访问时刻' )
url = models. CharField( max_length= 64 , verbose_name= '访问的URL' , help_text= '该用户访问的URL地址' )
device = models. CharField( max_length= 256 , null= True , verbose_name= '访问的浏览器' , help_text= '该用户是用什么浏览器访问的' )
platform = models. CharField( max_length= 256 , null= True , verbose_name= '访问的系统' , help_text= '该用户用的是什么操作系统' )
def __str__ ( self) :
return self. ip
class Meta :
ordering = [ 'id' ]
verbose_name_plural = '日志'
class UserInfo ( AbstractUser) :
avatar = models. FileField( upload_to= 'avatar/' , default= 'avatar/default.png' , verbose_name= '头像' , help_text= '该用户的头像' )
bg_img = models. FileField( upload_to= 'bg_img/' , default= 'bg_img/default_bg.png' , verbose_name= '头像' ,
help_text= '该用户的主页背景' )
province = models. CharField( max_length= 32 , default= '' , verbose_name= '省' , help_text= '该用户的省' )
city = models. CharField( max_length= 32 , default= '' , verbose_name= '城市' , help_text= '该用户的市' )
gender = models. IntegerField( choices= ( ( 0 , '保密' ) , ( 1 , '男' ) , ( 2 , '女' ) ) , default= 0 , verbose_name= '性别' ,
help_text= '该用户的性别' )
phone = models. CharField( max_length= 11 , null= True , default= '' , verbose_name= '联系方式' , help_text= '该用户的联系方式' )
blog = models. OneToOneField( to= 'Blog' , on_delete= models. CASCADE, null= True , verbose_name= '博客' , help_text= '该用户的博客' )
def __str__ ( self) :
return self. username
class Meta :
verbose_name_plural = '用户'
class Blog ( models. Model) :
title = models. CharField( max_length= 32 , verbose_name= '博主昵称' , help_text= '博主昵称' )
subtitle = models. CharField( max_length= 32 , verbose_name= '子标题/公告' , help_text= '博客的子标题/公告' )
style = models. CharField( max_length= 32 , verbose_name= '样式' , help_text= '该博客独有的样式' )
def __str__ ( self) :
return self. title
class Meta :
verbose_name_plural = '博客站点'
class Article ( models. Model) :
title = models. CharField( max_length= 32 , verbose_name= '标题' , help_text= '文章的标题' )
head_img = models. FileField( upload_to= 'article_head_img/' , default= 'article_head_img/default_head.png' ,
verbose_name= '头图' ,
help_text= '文章的头图' )
description = models. CharField( max_length= 128 , verbose_name= '摘要' , help_text= '简要描述该文章' )
content = models. TextField( verbose_name= '内容' , help_text= '文章的内容' )
markdown = models. TextField( verbose_name= 'Markdown内容' , default= '暂无' , help_text= '文章的Markdown内容' )
create_time = models. DateTimeField( auto_now_add= True , verbose_name= '创建时间' , help_text= '该文章的创建时间' )
modify_time = models. DateTimeField( auto_now= True , verbose_name= '修改时间' , help_text= '该文章的最后修改时间' )
up_num = models. IntegerField( default= 0 , verbose_name= '点赞数' , help_text= '该文章的点赞数' )
down_num = models. IntegerField( default= 0 , verbose_name= '点踩数' , help_text= '该文章的点踩数' )
comment_num = models. IntegerField( default= 0 , verbose_name= '评论数' , help_text= '该文章的评论数' )
blog = models. ForeignKey( to= 'Blog' , on_delete= models. CASCADE, null= True , blank= True , verbose_name= '博客' ,
help_text= '该文章属于哪个博客页面' )
category = models. ForeignKey( to= 'Category' , on_delete= models. CASCADE, null= True , blank= True , verbose_name= '分类' ,
help_text= '该文章属于哪个分类' )
tag = models. ManyToManyField( to= 'Tag' , through= 'Tag2Article' ,
through_fields= ( 'article' , 'tag' ) , verbose_name= '标签' ,
help_text= '该文章有哪些标签' )
def get_text_md ( self) :
return mark_safe( markdown( self. content) )
def __str__ ( self) :
return self. title
class Meta :
verbose_name_plural = '文章'
ordering = [ 'id' , ]
class Tag ( models. Model) :
name = models. CharField( max_length= 32 , verbose_name= '标签' , help_text= '标签的名字' )
blog = models. ForeignKey( to= 'Blog' , on_delete= models. DO_NOTHING, null= True , blank= True , verbose_name= '博客' ,
help_text= '该标签属于哪个博客页面' )
def __str__ ( self) :
return self. name
class Meta :
verbose_name_plural = '标签'
class Category ( models. Model) :
name = models. CharField( max_length= 32 , verbose_name= '分类' , help_text= '分类的名称' )
blog = models. ForeignKey( to= 'Blog' , on_delete= models. DO_NOTHING, null= True , blank= True , verbose_name= '博客' ,
help_text= '该分类属于哪个博客页面' )
def __str__ ( self) :
return self. name
class Meta :
verbose_name_plural = '分类'
class Comment ( models. Model) :
user = models. ForeignKey( to= 'UserInfo' , on_delete= models. DO_NOTHING, verbose_name= '用户' , help_text= '该评论来自哪个用户' )
article = models. ForeignKey( to= 'Article' , on_delete= models. CASCADE, null= True , verbose_name= '文章' ,
help_text= '评论的对象是哪篇文章' )
content = models. CharField( max_length= 256 , verbose_name= '内容' , help_text= '评论的内容' )
comment_time = models. DateTimeField( auto_now_add= True , verbose_name= '时间' , help_text= '评论的时间' )
comment_id = models. ForeignKey( to= 'self' , on_delete= models. CASCADE, null= True , verbose_name= '评论id' ,
help_text= '对哪个id的评论进行评论' )
def __str__ ( self) :
return self. content
class Meta :
verbose_name_plural = '评论'
class UpAndDown ( models. Model) :
user = models. ForeignKey( to= 'UserInfo' , on_delete= models. CASCADE, verbose_name= '用户' , help_text= '来自哪个用户' )
article = models. ForeignKey( to= 'Article' , on_delete= models. CASCADE, null= True , verbose_name= '文章' ,
help_text= '针对哪篇文章' )
is_up = models. BooleanField( null= True , verbose_name= '点赞点踩' , help_text= 'True为点赞,False为点踩' )
create_time = models. DateTimeField( auto_now_add= True , verbose_name= '创建时间' , help_text= '点赞点踩的时间' )
def __str__ ( self) :
return self. user
class Meta :
verbose_name_plural = '点赞点踩'
class Tag2Article ( models. Model) :
tag = models. ForeignKey( to= 'Tag' , on_delete= models. SET_DEFAULT, default= '' , verbose_name= '标签' , help_text= '关联的标签' )
article = models. ForeignKey( to= 'Article' , on_delete= models. CASCADE, default= '' , verbose_name= '文章' ,
help_text= '关联的文章' )
class Meta :
verbose_name_plural = '标签关联文章'
class Swiper ( models. Model) :
image = models. FileField( upload_to= 'swiper_img/' , default= 'swiper_img/default.jpg' , verbose_name= '图片' ,
help_text= '轮播图的图片' )
title = models. CharField( max_length= 32 , verbose_name= '标题' , help_text= '图片的标题' )
img_url = models. CharField( max_length= 64 , verbose_name= 'URL' , help_text= '点击图片要跳转的URL地址' )
def __str__ ( self) :
return self. img_url
class Meta :
verbose_name_plural = '轮播图'
django2表设计
from django. db import models
"""
先写普通字段
之后再写外键字段
"""
from django. contrib. auth. models import AbstractUser
class UserInfo ( AbstractUser) :
phone = models. BigIntegerField( verbose_name= '手机号' , null= True )
avatar = models. FileField( upload_to= 'avatar/' , default= 'avatar/default.png' , verbose_name= '用户头像' )
"""
给avatar字段传文件对象 该文件会自动存储到avatar文件下 然后avatar字段只保存文件路径avatar/default.png
"""
create_time = models. DateField( auto_now_add= True )
blog = models. OneToOneField( to= 'Blog' , null= True , on_delete= models. CASCADE)
class Blog ( models. Model) :
site_name = models. CharField( verbose_name= '站点名称' , max_length= 32 )
site_title = models. CharField( verbose_name= '站点标题' , max_length= 32 )
site_theme = models. CharField( verbose_name= '站点样式' , max_length= 64 )
class Category ( models. Model) :
name = models. CharField( verbose_name= '文章分类' , max_length= 32 )
blog = models. ForeignKey( to= 'Blog' , null= True , on_delete= models. CASCADE)
class Tag ( models. Model) :
name = models. CharField( verbose_name= '文章标签' , max_length= 32 )
blog = models. ForeignKey( to= 'Blog' , null= True , on_delete= models. CASCADE)
class Article ( models. Model) :
title = models. CharField( verbose_name= '文章标题' , max_length= 64 )
desc = models. CharField( verbose_name= '文章简介' , max_length= 255 )
content = models. TextField( verbose_name= '文章内容' )
create_time = models. DateField( auto_now_add= True )
up_num = models. IntegerField( verbose_name= '点赞数' , default= 0 )
down_num = models. IntegerField( verbose_name= '点踩数' , default= 0 )
comment_num = models. IntegerField( verbose_name= '评论数' , default= 0 )
blog = models. ForeignKey( to= 'Blog' , null= True , on_delete= models. CASCADE)
category = models. ForeignKey( to= 'Category' , null= True , on_delete= models. CASCADE)
tags = models. ManyToManyField( to= 'Tag' ,
through= 'Article2Tag' ,
through_fields= ( 'article' , 'tag' )
)
class Article2Tag ( models. Model) :
article = models. ForeignKey( to= 'Article' , on_delete= models. CASCADE)
tag = models. ForeignKey( to= 'Tag' , on_delete= models. CASCADE)
class UpAndDown ( models. Model) :
user = models. ForeignKey( to= 'UserInfo' , on_delete= models. CASCADE)
article = models. ForeignKey( to= 'Article' , on_delete= models. CASCADE)
is_up = models. BooleanField( )
class Comment ( models. Model) :
user = models. ForeignKey( to= 'UserInfo' , null= True , on_delete= models. CASCADE)
article = models. ForeignKey( to= 'Article' , null= True , on_delete= models. CASCADE)
content = models. CharField( verbose_name= '评论内容' , max_length= 255 )
comment_time = models. DateTimeField( verbose_name= '评论时间' , auto_now_add= True )
parent = models. ForeignKey( to= 'self' , null= True , on_delete= models. CASCADE)