管理信息系统 课程设计
管理信息系统 课程设计
系统概要说明
这是一个关于婚纱摄影的拍摄论坛,主要分享与吐槽婚纱拍摄及结婚过程中发生的美好事物和所遇的囧事。本设计基于Flask框架,利用PyCharm进行开发,使用了当前主流的AJAX技术进行数据传输,通过Json对数据进行判断,使得系统运行效率大大提高,获得更好的用户体验。在前端页面,添加JavaScript技术,令页面看起来更加美观舒适。
网站结构设计
本网站大致分为六大模块,分别是用户中心、论坛首页、拍摄推荐、婚庆分享、发布帖子和底部导航,每个版块相互独立又互为补充,保证了网站内容的丰富性,也满足不同访问者的个性需求,以下对模块进行介绍:
1、用户中心:网站的用户大致分为两类,分别是管理员和访问者,但无论如何都要通过登录才能行使对应的权限;
2、论坛首页:也称作首页,是论坛帖子主要展示的地方,也是整个网站内容最为丰富的地方,通过对数据库里的帖子进行遍历,展现出各种类型、板块的帖子;
3、拍摄推荐:这是为网站预留的推广页面,提供丰富多样的摄影服务,提高网站口碑;
4、婚庆分享:这也类似于推广,通过与婚庆公司合作进行客户引导消费,提高网站的盈利;
5、发布帖子:正如名称所见,这个版面主要用于发布帖子,论坛帖子的主要发布途径;
6、底部导航:图片导航设置在底部,里面记载各种结婚注意事项,体现网站关于结婚的专业性。
模块详细设计
1、用户:
(1)登录注册:通过对数据库进行添加信息或匹配校验实现登录注册功能;
(2)个人中心:个人中心细分为三个板块,分别是个人信息、已发布帖子和收藏帖子,它们共用一个页面,点击所在板块时进行显示;
1.个人信息:个人信息包括头像、用户名、邮箱号码、真实姓名、个性签名以及对以上信息进行删改;
2.已发布帖子:根据对用户id到数据库进行检索,展示出该用户曾经发布的帖子;
3.收藏帖子:在浏览页面时可对感兴趣的帖子进行收藏,收藏后在此处进行遍历展示;
2、头部导航:头部导航栏大致可以分为三个模块,分别是导航模块、搜索模块和登录注册;
(1)导航模块:点击对应按钮,可以进入到对应页面,实现不同功能;
(2)搜索模块:输入关键字进行搜索,根据关键字在数据库搜索完成后在页面显示成果;
(3)登录注册:通过点击实现登录注册,是用户实现功能的前提;
3、底部图片导航:底部使用了图片导航,当鼠标移动到图片时会产生放大效果,提高美观性;
4、帖子遍历:遍历数据库的所有帖子,并可以根据板块进行分类,展示标题和用户的简单信息,可以点击标题链接到详情页;
5、帖子发布:发布是论坛最主要的功能之一,页面发布与评论文本框采用ueditor封装架构,用网页语言对文本内容进行封装,丰富了内容例如添加表情、选择字体、添加图片等;
6、帖子详情:该页面对帖子内容进行全方位展示,大致包括详情展示、评论列表和评论输入,对于精彩的帖子还可以进行点赞收藏,增加了论坛帖子的趣味性。
数据库设计
整个网站所使用的数据库总共有六张表,分别是用户表、帖子表、评论表、板块表、点赞表和收藏表。
1、用户表
id:用户id(主键、自增长、默认值为shortuuid)
username:用户名(列属性、String类型、不可为空)
_password:用户密码(列属性、String类型、不可为空,设置哈希加密)
email:邮箱(列属性、String类型、不可重复、不可为空)
realname:真实姓名(列属性、String类型)
avatar:用户头像(列属性、String类型)
signature:个性签名(列属性、String类型)
join_time:加入时间(列属性、DateTime类型,默认值为添加时间)
2、帖子表
id:帖子id(主键、Int类型、自增长)
title:帖子标题(列属性、String类型、不可为空)
content:内容(列属性、Text类型、不可为空)
create_time:创建时间(列属性、DateTime类型、默认值为创建时间)
board_id:板块id(外键、Int类型、外键为border.id)
author_id:作者id(外键、String类型、外键为front_user.id)
3、评论表
id:帖子id(主键、Int类型、自增长)
content:内容(列属性、Text类型、不可为空)
create_time:创建时间(列属性、DataTime类型、默认值为创建时间)
post_id:帖子id(外键、Int类型、外键为post.id)
author_id:用户id(外键、String类型、外键为front_user.id)
4、板块表
id:板块id(主键、Int类型、自增长)
name:板块名称(列属性、String类型、不可为空)
create_time:创建时间(列属性、DataTime、默认值为创建时间)
5、点赞表
id:板块id(主键、Int类型、自增长)
post_id:帖子id(外键、Int类型、外键为post.id)
user_id:用户id(外键、String类型、外键为front_user.id)
6、收藏表
id:板块id(主键、Int类型、自增长)
user_id :用户id(外键、String类型、外键为front_user.id)
post_id:帖子id(外键、Int类型、外键为post.id)
create_time:创建时间(列属性、DateTime,默认值创建时间)
系统实现的关键算法与数据结构
def login_required(func):
@wraps(func)
def inner(*args,**kwargs):
if config.FRONT_USER_ID
in session:
return func(*args,**kwargs)
else:
return redirect(url_for('front.signin'))
return inner
class SignupForm(BaseForm):
email = StringField(validators=[Email(message='请输入正确的邮箱格式'), InputRequired(message='请输入邮箱')])
username = StringField(validators=[Regexp(r".{2,20}", message='请输入正确格式的用户名!')])
password1 = StringField(validators=[Regexp(r"[0-9a-zA-Z_\.]{6,20}", message='请输入正确格式的密码!')])
password2 = StringField(validators=[EqualTo("password1", message='两次输入的密码不一致!')])
class SigninForm(BaseForm):
email = StringField(validators=[Email(message='请输入正确的邮箱格式'), InputRequired(message='请输入邮箱')])
password = StringField(validators=[Regexp(r"[0-9a-zA-Z_\.]{6,20}", message='请输入正确格式的密码!')])
remeber = StringField()
class AddPostForm(BaseForm):
title = StringField(validators=[InputRequired(message='请输入标题!')])
content = StringField(validators=[InputRequired(message='请输入内容!')])
board_id = IntegerField(validators=[InputRequired(message='请输入板块id!')])
class AddCommentForm(BaseForm):
content = StringField(validators=[InputRequired(message='请输入评论内容!')])
post_id = IntegerField(validators=[InputRequired(message='请输入帖子id!')])
class ResetpwdForm(BaseForm):
oldpwd = StringField(validators=[Length(6,20,message='请输入正确格式的旧密码')])
newpwd = StringField(validators=[Length(6,20,message='请输入正确格式的新密码')])
newpwd2 = StringField(validators=[EqualTo("newpwd",message='确认密码必须和新密码保持一致')])
class UserupdataForm(BaseForm):
username = StringField(validators=[InputRequired(message='请输入用户名!')])
realname = StringField(validators=[InputRequired(message='请输入真实姓名!')])
@bp.before_request
def my_before_request():
if config.FRONT_USER_ID in session:
user_id = session.get(config.FRONT_USER_ID)
user = FrontUser.query.get(user_id)
if user:
g.front_user = user
@bp.errorhandler
def page_not_found():
return render_template('front/front_404.html'),404
class GenderEnum(enum.Enum):
MALE = 1
FEMALE = 2
SECRET = 3
UNKNOW = 4
class FrontUser(db.Model):
__tablename__='front_user'
id= db.Column(db.String(100),primary_key=True,default=shortuuid.uuid)
username = db.Column(db.String(50),nullable=False)
_password = db.Column(db.String(100),nullable=False)
email =db.Column(db.String(50),unique=True,nullable=False)
realname = db.Column(db.String(50))
avatar = db.Column(db.String(100)) #头像列
signature = db.Column(db.String(100)) #个性签名
join_time = db.Column(db.DateTime,default=datetime.now)
def __init__(self,*args,**kwargs):
if "password" in kwargs:
self.password = kwargs.get('password')
kwargs.pop("password")
super(FrontUser,self).__init__(*args,**kwargs)
@property
def passwoed(self):
return self._password
@passwoed.setter
def password(self,newpwd):
self._password= generate_password_hash(newpwd)
def check_password(self,rawpwd):
return check_password_hash(self._password,rawpwd)
from .forms import SignupForm,SigninForm,AddPostForm,AddCommentForm,ResetpwdForm,UserupdataForm
from utils import restful,safeutils
from .models import FrontUser
from ..models import BoardModel,PostModel,CommentModel,HighlightPostModel,DianzanModel,Collection
from exts import db
import config,os
from .decorators import login_required
from flask_paginate import Pagination,get_page_parameter
from sqlalchemy import or_,and_
bp = Blueprint("front",__name__)
@bp.route('/hignlight')
def hignlight():
post = PostModel.query.all()
return render_template('front/front_allpost.html',post=post)
@bp.route('/hpost',methods=['POST'])
def hpost():
post_id = request.form.get("post_id")
if not post_id:
return restful.params_error('请传入帖子id')
post=PostModel.query.get(post_id)
if not post:
return restful.params_error("没有这篇帖子!")
hignlight = HighlightPostModel()
hignlight.post = post
db.session.add(hignlight)
db.session.commit()
return restful.success()
@bp.route('/upost',methods=['POST'])
def upost():
post_id = request.form.get("post_id")
if not post_id:
return restful.params_error('请传入帖子id')
post=PostModel.query.get(post_id)
if not post:
return restful.params_error("没有这篇帖子!")
hignlight = HighlightPostModel.query.filter_by(post_id=post_id).first()
db.session.delete(hignlight)
db.session.commit()
return restful.success()
@bp.route('/')
def index():
board_id = request.args.get('bd',type=int,default=None)
page = request.args.get(get_page_parameter(),type=int, default=1)
boards = BoardModel.query.all()
start =(page-1)*config.PER_PAGE
end = start + config.PER_PAGE
posts=None
total = 0
query_obj=PostModel.query.order_by(PostModel.create_time.desc())
if board_id:
query_obj = query_obj.filter_by(board_id=board_id)
posts = query_obj.slice(start,end)
total = query_obj.count()
else:
posts = query_obj.slice(start,end)
total = query_obj.count()
pagination = Pagination(bs_version=3,page=page,total=total,outer_window=0,inner_window=2)
context={
'boards': boards,
'posts':posts,
'pagination':pagination,
'current_board':board_id
}
return render_template('front/front_index.html',**context)
@bp.route('/p/<post_id>')
def post_detail(post_id):
post = PostModel.query.get(post_id)
if not post:
abort('404')
dzyes = DianzanModel.query.filter( # dzyes用在用户详情页判断是否已点赞的按钮
and_(
DianzanModel.user_id == g.front_user.id, DianzanModel.post_id == post_id
)
).first()
collection = Collection.query.filter(
and_(
Collection.user_id == g.front_user.id, Collection.post_id == post_id
)
).first()
return render_template('front/front_pdetail.html',post=post,dzyes=dzyes,collection=collection)
@bp.route('/acomment/',methods=['POST'])
@login_required
def add_comment():
form = AddCommentForm(request.form)
if form.validate():
content = form.content.data
post_id = form.post_id.data
post= PostModel.query.get(post_id)
if post:
comment=CommentModel(content=content)
comment.post=post
comment.author = g.front_user
db.session.add(comment)
db.session.commit()
return restful.success()
else:
return restful.params_error('没有这篇帖子')
else:
return restful.params_error(form.get_error())
@bp.route('/apost/',methods=['GET','POST'])
@login_required
def apost():
if request.method == 'GET':
boards = BoardModel.query.all()
return render_template('front/front_apost.html', boards=boards)
else:
form = AddPostForm(request.form)
if form.validate():
title = form.title.data
content = form.content.data
board_id = form.board_id.data
board = BoardModel.query.get(board_id)
if not board:
return restful.params_error(message='没有这个板块!')
post = PostModel(title=title, content=content)
post.board = board
post.author= g.front_user
db.session.add(post)
db.session.commit()
return restful.success()
else:
return restful.params_error(message=form.get_error())
#个人中心
@bp.route('/usercenter/<user_id>/<tag>')
@login_required
def usercenter(user_id,tag):
user = FrontUser.query.filter(FrontUser.id==user_id).first()
posts = PostModel.query.filter(PostModel.author_id == user_id).all()
collection=Collection.query.filter(Collection.user_id==user_id).all()
context = {
'user':user,
'posts':posts,
'collection':collection
}
if tag == '1':
return render_template('front/front_usercenter.html',**context)
if tag == '2':
return render_template('front/front_user_apost.html',**context)
else:
return render_template('front/front_user_collection.html',**context)
#点赞功能
@bp.route('/dianzan/',methods=['GET','POST'])
@login_required
def dianzan():
user_id=g.front_user.id
post_id=request.form.get('post_id')
dianzan=DianzanModel(user_id=user_id,post_id=post_id)
db.session.add(dianzan)
db.session.commit()
return redirect(url_for('front.post_detail',post_id=post_id))
#收藏
@bp.route('/collection/',methods=['GET','POST'])
@login_required
def collection():
user_id=g.front_user.id
post_id=request.form.get('post_id')
collection=Collection(user_id=user_id,post_id=post_id)
db.session.add(collection)
db.session.commit()
return redirect(url_for('front.post_detail',post_id=post_id))
#用户上传头像
@bp.route('/avatar/<user_id>',methods=['POST'])
@login_required
def updata_acatar(user_id):
user = FrontUser.query.filter(FrontUser.id == user_id).first()
f = request.files['img']
basepath = os.path.dirname(__file__) # 当前文件所在路径
upload_path = os.path.join('D:/godlike/static/img', f.filename) # 注意:没有的文件夹一定要先创建,不然会提示没有该路径
f.save(upload_path)
user.avatar = 'img/' + f.filename
db.session.commit()
return redirect(url_for('front.usercenter',user_id=user.id,tag=1))
#用户修改个人信息
@bp.route('/user_updata/<user_id>',methods=['GET','POST'])
@login_required
def user_updata(user_id):
if request.method == 'GET':
user= FrontUser.query.filter(FrontUser.id==user_id).first()
return render_template('front/front_user_updata.html',user=user)
else:
form = UserupdataForm(request.form)
if form.validate():
username = form.username.data
realname = form.realname.data
signature = request.form.get('signature')
user = g.front_user
user.username =username
user.realname = realname
user.signature = signature
db.session.commit()
return restful.success()
else:
return restful.params_error(form.get_error())
#用户修改密码
@bp.route('/resetpwd/',methods=['GET','POST'])
@login_required
def resetpwd():
if request.method == 'GET':
return render_template('front/front_resetpwd.html')
else:
form = ResetpwdForm(request.form)
if form.validate():
oldpwd = form.oldpwd.data
newpwd = form.newpwd.data
user = g.front_user
if user.check_password(oldpwd):
user.password = newpwd
db.session.commit()
# {"code":200,message=""}
# return jsonify({"code":200,"message":""})
return restful.success()
else:
return restful.params_error("旧密码错误!")
else:
return restful.params_error(form.get_error())
#注销
@bp.route('/logout/')
@login_required
def logout():
del session[config.FRONT_USER_ID]
return redirect(url_for('front.index'))
#注册功能后台视图
class SignupView(views.MethodView):
def get(self):
return_to = request.referrer
if return_to and return_to != request.url and safeutils.is_safe_url(return_to):
return render_template('front/front_signup.html',return_to=return_to)
else:
return render_template('front/front_signup.html')
def post(self):
form = SignupForm(request.form)
if form.validate():
email = form.email.data
username = form.username.data
password = form.password1.data
user = FrontUser(email=email,username=username,password=password)
db.session.add(user)
db.session.commit()
return restful.success()
else:
print(form.get_error())
return restful.params_error(message=form.get_error())
#登录功能后台视图
class SigninView(views.MethodView):
def get(self):
return_to = request.referrer
if return_to and return_to != request.url and return_to != url_for("front.signup") and safeutils.is_safe_url(
return_to):
return render_template('front/front_signin.html', return_to=return_to)
else:
return render_template('front/front_signin.html')
def post(self):
form =SigninForm(request.form)
if form.validate():
email = form.email.data
password = form.password.data
remember = form.remeber.data
user = FrontUser.query.filter_by(email=email).first()
if user and user.check_password(password):
session[config.FRONT_USER_ID]=user.id
if remember:
session.permanent= True
return restful.success()
else:
return restful.params_error(message='邮箱或密码错误!')
else:
return restful.params_error(message=form.get_error())
class BoardModel(db.Model):
__tablename__='board'
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
name = db.Column(db.String(20),nullable=False)
create_time = db.Column(db.DateTime,default=datetime.now)
class PostModel(db.Model):
__tablename__ ='post'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(200),nullable=False)
content = db.Column(db.Text,nullable=False)
create_time = db.Column(db.DateTime,default=datetime.now)
board_id = db.Column(db.Integer,db.ForeignKey("board.id"))
author_id = db.Column(db.String(100),db.ForeignKey("front_user.id"),nullable=False)
author = db.relationship("FrontUser",backref="posts")
board=db.relationship("BoardModel",backref="posts")
class CommentModel(db.Model):
__tablename__='comment'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
content = db.Column(db.Text,nullable=False)
create_time = db.Column(db.DateTime,default=datetime.now)
post_id = db.Column(db.Integer,db.ForeignKey("post.id"),nullable=False)
author_id = db.Column(db.String(100),db.ForeignKey("front_user.id"),nullable=False)
post = db.relationship("PostModel",backref='comments')
author = db.relationship("FrontUser",backref='comments')
class HighlightPostModel(db.Model):
__tablename__='highlight_post'
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
post_id = db.Column(db.Integer,db.ForeignKey("post.id"))
create_time = db.Column(db.DateTime,default=datetime.now)
post=db.relationship("PostModel",backref="highlight")
class DianzanModel(db.Model):
__tablename__ = 'dianzan'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
post_id = db.Column(db.Integer, db.ForeignKey("post.id"), nullable=False)
user_id = db.Column(db.String(100), db.ForeignKey("front_user.id"), nullable=False)
post = db.relationship("PostModel", backref=("dianzan"))
user = db.relationship("FrontUser", backref=("dianzan"))
class Collection(db.Model):
__tablename__='collection'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
post_id = db.Column(db.Integer, db.ForeignKey("post.id"), nullable=False)
user_id = db.Column(db.String(100), db.ForeignKey("front_user.id"), nullable=False)
create_time = db.Column(db.DateTime, default=datetime.now)
post = db.relationship("PostModel", backref=("collection"))
user = db.relationship("FrontUser", backref=("collection"))
class BaseForm(Form):
def get_error(self):
message = self.errors.popitem()[1][0]
return message
def validate(self):
return super(BaseForm, self).validate()