1 系统概要说明
1.1 目的
在前期Python的基础课程中学习到了turtle库的基础练习、字符串的基本操作、凯撒密码 、GDP格式化输出、99乘法表、中英文词频统计、和datetime处理日期和时间等等基础学习。
其中最有趣的也是最简单的就是turtle库的基础练习,画出五角星,比较好玩,在后来网页制作的课程中我学习各种网页前端页面的效果,还有后台连接数据库,并学会在网页上利用pysql库代码对数据库的数据进行增删查改,在页面显示效果。
最后做出了一个较为粗糙的论坛网站,模仿了老师上课讲的,看了截图,请教了同学才做出一个简单的网站。
在今后还会继续学习Python的。我刚刚开始接触到Python这门编程语言的时候,就发现相比以往学习的java这门编程语言中,这门语言更容易入门,代码较为精简,而功能非常齐全,不止可以用来制作网页,而且可以进行数据挖掘,而我在学习中可以很快的上手,并且比较有兴趣的去打代码,不像以往打JAVA代码一样非常的烦闷,可以较为轻松的心态去做好Python。
有一句程序员们调侃的一句话,叫:”人生苦短,我学Python”。
项目本身的python代码就不多,但是功能却十分完善,可以很好地上面那一句调侃的话。
同学们也可以在闲的时候来我的平台上发布一些评论和看法,大家一起多多交流一下,我们的学习情况,还有生活。
1.2 系统主要框架与技术
系统采用Python的Flask轻量级服务器端的框架,并且使用的是jinja2模板引擎做到了前后台代码分离。Bootstrap下的DIV+CSS开发模式。
2 网站结构设计
2.1 网站结构图
推荐文章 |
评论 |
点赞 |
收藏 |
评论分享网 |
首页 |
文章详情 |
个人中心 |
文章发布 |
热门文章 |
文章列表 |
高级搜索 |
文章分类 |
注册 |
登陆 |
上传头像 |
修改密码 |
我的收藏 |
我的发布 |
我的评论 |
分类 |
2.2 布局方案
网站的结构就是通过使用结构化的方法,对网页中所需的信息进行整理以及是分类,使得网站的内容更具有条理性、逻辑性和清晰性。相信很多网站建设者在改版网站的时候,都会发现很多网站都没有自己的结构格局,一打开网站的页面就像一团布满折痕的废纸一样,用户是很难在里面找到自己想要的信息的。这就好比读者在打开一本小说,突然发现里面没有了段落以及标点,而且字间也没有间隙,笔者相信不出几秒,读者必定会觉得头晕眼花。所以一个好的结构是页带来好的用户体验的重要的一环。
网站结构的表现则是通过技术对已经被构化的信息进行显示上的控制,比如说版式、颜色小等样式的控制。表现是结构的一种升华,仅仅只是有合理的条理是不够的,还要做到让人赏心悦目,让别人更加喜欢网站,给人一种眼前一 亮的感觉。一本好书除了要有好的内容外,还有点很重要的是能吸引人的眼球,别人第一眼喜欢上了你的表现,才能进一步的对的内容产生兴趣。
本站在设计上就采用精简,功能明确,不需要过多的冗余。
2.3 功能用法
详情页是指文章点进去后,显示文章内容的页面,其中还包括以下:
1) 推荐文章。推荐你喜欢的文章。
2) 评论。对这篇文章你的看法是如何的。
3) 点赞。觉得写的好,就点个赞吧。
4) 收藏。把你认为好的,以后还会看收藏起来,在我的个人中心,以后还可以点开来看
首页主要包括:
1) 热门文章。给用户推荐平台上,点击数量最大的前五本书,让用户可以了解大家都喜欢什么样的书。
2) 文章列表。每一本书的标题、时间、作者、分享还有简介的摘要也会以一条条的形式显示在首页,而且每一秒都会显示再新的分享。
3) 高级搜索。单一的搜索只能找到书中有过的关键字,高级搜索可以将多个条件同时录入进行搜索。
4) 文章分类。以类别分别显示文章列表。
5) 注册。新用户注册平台账号。
6) 登陆。登录账号去管理个人中心中的个人信息。
对于有以登录的用户,平台还提供了个人中心去管理自己的信息:
1) 上传头像。用户可以自定义自己的头像,默认是一个黑色的头像,上传有自己个性的头像,可以让别人更加容易记得自己。
2) 修改密码。为了账号安全,定期修改密码。
3) 我的收藏。把你认为好的,以后还会看收藏起来,在我的个人中心,以后还可以点开来看。
3 模块详细设计
# 退出
@app.route('/logout/')
def logout():
session.pop('username')
return redirect(url_for('index'))
# 上下文
@app.context_processor
def myContext():
username = session.get('username')
if username:
user = User.query.filter(User.username == username).first()
else:
user = {}
if user:
return {'user_id': user.id, 'user': user}
else:
return {}
# 登陆
@app.route('/login/', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
else:
username = request.form.get('username')
password = request.form.get('password')
user = User.query.filter(User.username == username).first()
if user:
if user.check_password(password):
session['username'] = user.username
session['user_id'] = user.id
session.permanent = True
# 重新定位到首页
return redirect(url_for('index'))
else:
# 重新定位到注册
return redirect(url_for('login'))
else:
return redirect(url_for('login'))
# 注册
@app.route('/regist/', methods=['GET', 'POST'])
def regist():
if request.method == 'GET':
# 打开注册页的模板
return render_template('regist.html')
else: # 收到用户上传的信息
username = request.form.get('username')
password = request.form.get('password')
user = User.query.filter(User.username == username).first()
if user:
return 'error:user exitst'
else:
user = User(username=username, password=password)
db.session.add(user) # 加入数据库
db.session.commit()
return redirect(url_for('login'))
# 定义一个装饰器出验证用户有是否是登陆
# 定义一个参数函数
def loginFirst(func):
# 定义一个函数将其返回
@wraps(func)
def wrapper(*args, **kwargs):
if session.get('username'):
return func(*args, **kwargs)
else:
return redirect(url_for('login'))
# 返回一个函数
return wrapper
#修改密码
@app.route('/setPassword/
@loginFirst
def setPassword(id):
if request.method == 'GET':
return render_template('setPassword.html')
else:
user = User.query.filter(User.id == id).first()
if user:
if user.check_password(request.form.get('old')):
user.password = request.form.get('new1')
db.session.commit()
info = '修改成功'
else:
info = '原密码错误'
else:
info = '未知错误'
return redirect(url_for('index', info=info))
# 发布问答
@app.route('/question', methods=['GET', 'POST'])
@loginFirst
def question():
if request.method == 'GET':
cf = Cf.query.all()
return render_template('question.html', cf=cf)
else:
title = request.form.get('title')
detail = request.form.get('detail')
author_id = request.form.get('author_id')
cf = request.form.get('cf')
question = Question(title=title, detail=detail, author_id=author_id, cf=cf)
db.session.add(question) # 加入数据库
db.session.commit()
return redirect(url_for('index'))
# 发布评论
@app.route('/answer/', methods=['GET', 'POST'])
def answer():
if request.method == 'POST':
question_id = request.form.get('question_id')
author_id = request.form.get('author_id')
detail = request.form.get('detail')
comment = Comment(question_id=question_id, author_id=author_id, detail=detail)
db.session.add(comment)
db.session.commit()
return redirect(url_for('detail', question_id=question_id))
# 首页
@app.route('/')
def index():
if request.args.get('info'):
info = request.args.get('info')
else:
info = None;
context = {
'questions': Question.query.order_by('-creat_time').all(),
'cf': Cf.query.all(),
'info': info,
'hot': Question.query.order_by('-click').all()[0:5]
}
return render_template('index.html', **context)
# 某用户发布过的所有评论
@app.route('/comment/
def comment(user_id, num):
user = User.query.filter(User.id == user_id).first()
content = {
'comment': user.comment,
'questions': user.question,
'user2': user,
}
if (num == '1'):
return render_template('subComment1.html', **content, title='全部问题')
elif (num == '2'):
return render_template('subComment2.html', **content)
elif (num == '3'):
return render_template('subComment3.html', **content)
elif (num == '4'):
content = {
'comment': user.comment,
'questions': user.collection.all(),
'user2': user,
}
return render_template('subComment1.html', **content, title='我的收藏')
else:
return render_template('subComment1.html', **content)
#分类显示
@app.route('/c/
def c(cf):
content = {
'questions': Question.query.filter(Question.cf == cf).order_by('-creat_time').all(),
'cf': Cf.query.all(),
'hot': Question.query.order_by('-click').all()[0:5]
}
return render_template('index.html', **content)
# 详情页
@app.route('/detail/
@loginFirst
def detail(question_id):
quest = Question.query.filter(Question.id == question_id).first()
u = User.query.filter(User.id == session.get('user_id')).first()
if request.method == 'POST':
if request.form.get('click') == '1':
quest.click = quest.click + 1
if request.form.get('collection') == '1':
user = u
user.collection.append(quest)
db.session.add(user)
col = u.collection.filter_by(id=question_id).first()
if col is None:
col = {}
comment = Comment.query.filter(Comment.question_id == question_id).order_by('-creat_time').all()
quest.look = quest.look + 1
db.session.commit()
content = {
'ques': quest,
'comment': comment,
'col': col,
'questions': Question.query.filter(Question.cf == quest.cf).all(),
}
return render_template('detail.html', **content)
4 数据库设计
4.1 E-R图
头像地址 |
注册日期 |
收藏 |
日期 |
评论 |
用户 |
编号 |
密码 |
显示名称 |
登录账号名 |
分类 |
分类编号 |
名称 |
编号 |
问题 |
标题 |
发布时间 |
发布者 |
内容 |
头像 |
阅读数 |
点击数 |
日期 |
内容 |
4.2 程序模型现实
# 收藏表
Collection = db.Table(
'collection',
db.Column('id', db.Integer, primary_key=True, autoincrement=True),
db.Column('book_id', db.Integer, db.ForeignKey('question.id')), # 评论对应的文章的id
db.Column('collection', db.Integer, db.ForeignKey('user.id')), # 收藏用户的id
db.Column('createdate', db.DATETIME) # 发布时间
)
#用户表
class User(db.Model):
__tablename__ = 'user'
# 建立一个表user
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(20), nullable=False)
_password = db.Column(db.String(200), nullable=False)
say = db.Column(db.String(50))
icon = db.Column(db.String(50), default='uploads/default_logo.jpg')
collection = db.relationship('Question', secondary=Collection, backref=db.backref('user', lazy='dynamic'),
lazy='dynamic')
@property
def password(self):
return self._password
@password.setter
def password(self, row_password):
self._password = generate_password_hash(row_password)
def check_password(self, row_password):
return check_password_hash(self._password, row_password)
#评论表
class Comment(db.Model):
__tablename__ = 'comment'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
author_id = db.Column(db.Integer, db.ForeignKey('user.id'))
question_id = db.Column(db.Integer, db.ForeignKey('question.id'))
creat_time = db.Column(db.DateTime, default=datetime.now())
detail = db.Column(db.TEXT, nullable=False)
question = db.relationship('Question', backref=db.backref('comment'))
author = db.relationship('User', backref=db.backref('comment', order_by=creat_time.desc))
#问题表
class Question(db.Model):
__tablename__ = 'question'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(100), nullable=False)
detail = db.Column(db.Text, nullable=False)
creat_time = db.Column(db.DateTime, default=datetime.now)
author_id = db.Column(db.Integer, db.ForeignKey('user.id'))
cf = db.Column(db.Integer, db.ForeignKey('cf.id'))
look = db.Column(db.Integer, default=0)
click = db.Column(db.Integer, default=0)
author = db.relationship('User', backref=db.backref('question'))
cfClass = db.relationship('Cf', backref=db.backref('question'))
# 分类
class Cf(db.Model):
__tablname__ = 'cf'
id = db.Column(db.Integer, primary_key=True, autoincrement=True) # 数据库唯识别id
name = db.Column(db.String(30)) # 文章名称
context = db.Column(db.TEXT) # 分类内容
5 系统实现的关键算法与数据结构
5.1 上传头像
# 上传头像
@app.route('/uploadLogo/
def uploadLogo(user_id):
user = User.query.filter(User.id == user_id).first()
f = request.files['logo']
basepath = os.path.dirname(__file__) # 当前文件所在路径
upload_path = os.path.join(basepath, 'static/uploads', f.filename) # 注意:没有的文件夹一定要先创建,不然会提示没有该路径
f.save(upload_path)
user.icon = 'uploads/' + f.filename
db.session.commit()
return redirect(url_for('setPassword', id=user_id)); 5.2 前面用户账号密码检
5.2 高级搜索的算法
# 模糊查找
@app.route('/search')
def search():
qu = request.args.get('q')
c = '' if request.args.get('c') == '' else request.args.get('c')
y = '' if request.args.get('y') == '' else request.args.get('y')
query = Question.query.filter(
or_(
Question.title.contains(qu),
Question.detail.contains(qu),
),
Question.cf.like('%' + c + '%'),
Question.creat_time.like('%' + y + '%'),
).order_by('-creat_time').all()
context = {
'questions': query,
'cf': Cf.query.all(),
'hot': Question.query.order_by('-click').all()[0:5]
}
return render_template('index.html', **context)
前端代码:
6 成品展示
网站父模板统一布局
这些页面全部继承与父模板,导航就是父模板中的
注册、登录、注销
发布、列表显示
详情页
评论、列表显示
个人中心
高级搜索
文章分类、显示
点赞、收藏
修改密码、头像、上传头像
热门文章、推荐文章