摘要
博客是典型的CMS(Content Management System,内容管理系统),通常由两部分组成:一部分是博客前台,用来展示开放给所有用户的博客内容;另一部分是博客后台,这部分内容仅开放给博客管理员,用来对博客资源进行添加、修改和删除等操作。本文通过分析个人博客的功能需求,采用 python 的web 框架flask实现一个个人博客系统。
1、引言
本文旨在开发一个个人博客系统,采用的程序设计语言是python,web 开发框架是flask,数据库是 SQLite。
Python是一种跨平台的计算机程序设计语言。是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越多被用于独立的、大型项目的开发。
Flask是一个轻量级的可定制框架,使用Python语言编写,较其他同类型框架更为灵活、轻便、安全且容易上手。它可以很好地结合MVC模式进行开发,开发人员分工合作,小型团队在短时间内就可以完成功能丰富的中小型网站或Web服务的实现。另外,Flask还有很强的定制性,用户可以根据自己的需求来添加相应的功能,在保持核心功能简单的同时实现功能的丰富与扩展,其强大的插件库可以让用户实现个性化的网站定制,开发出功能强大的网站。
SQLite,是一款轻型的数据库,是关系型数据库管理系统,在 python 中内置了 SQLite库。本文采用 SQLite 进行快速开发与测试。
本文结构如下:
第一章, 引言。介绍本文目的,采用技术介绍和文章结构。
第二章, 需求分析,详细分析了个人博客系统的功能需求。
第三章, 数据库分析与设计。详细介绍了个人博客系统的数据库表设计与实现。
第四章, 详细设计。介绍了个人模块系统的项目结构、功能模块及其代码实现。
第五章, 实验结果。介绍了个人博客系统的实现效果。
第六章, 总结和展望。介绍对项目开发的经验总结以及系统的不足与完善目标。
2、需求分析
2.1 功能需求
个人博客系统主要分为三个模块,分别为:博客前台、博客后台、用户认证。
2.1.1 博客前台
博客前台展示博客文章信息,功能如下:
- 文章列表(主页):网站主页显示-- 博客文章列表。
- 文章详情页面:页面显示博客文章的详情。
- 评论列表:在博客文章详情页面显示评论列表。
- 发表评论:在博客文章详情页面对文章发表评论。
- 回复评论:在评论列表中回复评论。
2.1.2 博客后台
博客后台为博客管理员对博客进行管理,功能如下:
- 文章管理功能,创建文章,更新文章,删除文章。
- 管理分类功能,创建分类,更新分类,删除分类。
- 管理评论功能,关闭文章评论,删除文章评论,审核评论,评论筛选。
博客资料设置,置博客信息。
2.1.3用户认证
创建管理源账户
用户登陆功能
2.2 功能结构图
3、数据库设计
3.1 数据库表设计
3.1.1 管理员
字段名 | 类型 | 大小 | 备注 |
---|---|---|---|
id | 是 | 是 | |
username | 是 | 是 | |
password | 否 | 否 | |
blog_title | 是 | 否 | |
blog_subtitle | 否 | 否 |
3.2 E-R 图
4、设计实现
4.1 项目结构
blog/
blueprint/ 功能模块
- __init__.py
- blog.py 博客前台
- auth.py 用户认证
- admin.py 博客后台
templates/ 页面模板
- admin/ 后台页面
- auth/ 认证页面
- blog/ 前台页面
- base.html
- macros.html
static/ 静态资源
forms.py 表单
models.py 数据模型
email.py 邮箱验证
utils.py 辅助
fakes.py 虚拟数据
extensions.py 扩展
4.2 数据模型实现
4.2.1 管理员
class Admin(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20))
password_hash = db.Column(db.String(128))
blog_title = db.Column(db.String(60))
blog_sub_title = db.Column(db.String(100))
name = db.Column(db.String(30))
about = db.Column(db.Text)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def validate_password(self, password):
return check_password_hash(self.password_hash, password)
4.2.2 分类
lass Category(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30), unique=True)
posts = db.relationship('Post', back_populates='category')
def delete(self):
default_category = Category.query.get(1)
posts = self.posts[:]
for post in posts:
post.category = default_category
db.session.delete(self)
db.session.commit()
4.2.4 评论
class Comment(db.Model):
id = db.Column(db.Integer, primary_key=True)
author = db.Column(db.String(30))
email = db.Column(db.String(254))
site = db.Column(db.String(255))
body = db.Column(db.Text)
from_admin = db.Column(db.Boolean, default=False)
reviewed = db.Column(db.Boolean, default=False)
timestamp = db.Column(db.DateTime, default=datetime.utcnow, index=True)
replied_id = db.Column(db.Integer, db.ForeignKey('comment.id'))
post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
post = db.relationship('Post', back_populates='comments')
replies = db.relationship('Comment', back_populates='replied', cascade='all, delete-orphan')
replied = db.relationship('Comment', back_populates='replies', remote_side=[id])
4.3 功能实现
4.3.1 博客前台
1、首页
@blog_bp.route('/')
def index():
page = request.args.get('page', 1, type=int)
per_page = current_app.config['BLUELOG_POST_PER_PAGE']
pagination = Post.query.order_by(Post.timestamp.desc()).paginate(page, per_page=per_page)
posts = pagination.items
return render_template('blog/index.html', pagination=pagination, posts=posts)
2、分类页面
@blog_bp.route('/category/<int:category_id>')
def show_category(category_id):
category = Category.query.get_or_404(category_id)
page = request.args.get('page', 1, type=int)
per_page = current_app.config['BLUELOG_POST_PER_PAGE']
pagination = Post.query.with_parent(category).order_by(Post.timestamp.desc()).paginate(page, per_page)
posts = pagination.items
return render_template('blog/category.html', category=category, pagination=pagination, posts=posts)
3、文章页面
@blog_bp.route('/post/<int:post_id>', methods=['GET', 'POST'])
def show_post(post_id):
post = Post.query.get_or_404(post_id)
page = request.args.get('page', 1, type=int)
per_page = current_app.config['BLUELOG_COMMENT_PER_PAGE']
pagination = Comment.query.with_parent(post).filter_by(reviewed=True).order_by(Comment.timestamp.asc()).paginate(
page, per_page)
comments = pagination.items
if current_user.is_authenticated:
form = AdminCommentForm()
form.author.data = current_user.name
form.email.data = current_app.config['BLUELOG_EMAIL']
form.site.data = url_for('.index')
from_admin = True
reviewed = True
else:
form = CommentForm()
from_admin = False
reviewed = False
if form.validate_on_submit():
author = form.author.data
email = form.email.data
site = form.site.data
body = form.body.data
comment = Comment(
author=author, email=email, site=site, body=body,
from_admin=from_admin, post=post, reviewed=reviewed)
replied_id = request.args.get('reply')
if replied_id:
replied_comment = Comment.query.get_or_404(replied_id)
comment.replied = replied_comment
send_new_reply_email(replied_comment)
db.session.add(comment)
db.session.commit()
if current_user.is_authenticated: # send message based on authentication status
flash('Comment published.', 'success')
else:
flash('Thanks, your comment will be published after reviewed.', 'info')
send_new_comment_email(post) # send notification email to admin
return redirect(url_for('.show_post', post_id=post_id))
return render_template('blog/post.html', post=post, pagination=pagination, form=form, comments=comments)
4、评论功能
@blog_bp.route('/reply/comment/<int:comment_id>')
def reply_comment(comment_id):
comment = Comment.query.get_or_404(comment_id)
if not comment.post.can_comment:
flash('Comment is disabled.', 'warning')
return redirect(url_for('.show_post', post_id=comment.post.id))
return redirect(
url_for('.show_post', post_id=comment.post_id, reply=comment_id, author=comment.author) + '#comment-form')
4.3.2 博客后台
1、文章管理
@admin_bp.route('/post/manage')
@login_required
def manage_post():
page = request.args.get('page', 1, type=int)
pagination = Post.query.order_by(Post.timestamp.desc()).paginate(
page, per_page=current_app.config['BLUELOG_MANAGE_POST_PER_PAGE'])
posts = pagination.items
return render_template('admin/manage_post.html', page=page, pagination=pagination, posts=posts)
2、评论管理
@admin_bp.route('/comment/manage')
@login_required
def manage_comment():
filter_rule = request.args.get('filter', 'all') # 'all', 'unreviewed', 'admin'
page = request.args.get('page', 1, type=int)
per_page = current_app.config['BLUELOG_COMMENT_PER_PAGE']
if filter_rule == 'unread':
filtered_comments = Comment.query.filter_by(reviewed=False)
elif filter_rule == 'admin':
filtered_comments = Comment.query.filter_by(from_admin=True)
else:
filtered_comments = Comment.query
pagination = filtered_comments.order_by(Comment.timestamp.desc()).paginate(page, per_page=per_page)
comments = pagination.items
return render_template('admin/manage_comment.html', comments=comments, pagination=pagination)
3、分类管理
@admin_bp.route('/category/manage')
@login_required
def manage_category():
return render_template('admin/manage_category.html')
4、博客设置
@admin_bp.route('/settings', methods=['GET', 'POST'])
@login_required
def settings():
form = SettingForm()
if form.validate_on_submit():
current_user.name = form.name.data
current_user.blog_title = form.blog_title.data
current_user.blog_sub_title = form.blog_sub_title.data
current_user.about = form.about.data
db.session.commit()
flash('Setting updated.', 'success')
return redirect(url_for('blog.index'))
form.name.data = current_user.name
form.blog_title.data = current_user.blog_title
form.blog_sub_title.data = current_user.blog_sub_title
form.about.data = current_user.about
return render_template('admin/settings.html', form=form)
4.3.3 用户认证
1、登陆
@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('blog.index'))
form = LoginForm()
if form.validate_on_submit():
username = form.username.data
password = form.password.data
remember = form.remember.data
admin = Admin.query.first()
if admin:
if username == admin.username and admin.validate_password(password):
login_user(admin, remember)
flash('Welcome back.', 'info')
return redirect_back()
flash('Invalid username or password.', 'warning')
else:
flash('No account.', 'warning')
return render_template('auth/login.html', form=form)
2、登出
@auth_bp.route('/logout')
@login_required
def logout():
logout_user()
flash('Logout success.', 'info')
return redirect_back()
5、 实验结果
5.1 博客前台
5.1.1 首页
5.1.2 文章页面
5.1.3 评论列表
6、总结与展望
6.1 学习总结
在开发个人博客系统的过程中,遇到了许多困难,也学习到了许多新的知识。遇到的困难主要是陌生技术/框架的掌握上,在开发系统的过程中,需要引入新的技术/框架,由于新技术/框架的原理或者知识领域相对陌生,在掌握的过程中存在一些困难。在解决这些困难的工程中,一并掌握了这些新技术/框架的原理和领域知识。
在开发本系统的过程中,掌握了许多知识。本系统采用 flask web 开发框架,由此学习了web 开发技术,http 原理,B/S架构模式等知识。系统还使用 fakes 库产生虚拟数据,进行数据填充,学习掌握产生虚拟数据的方法。系统使用SQLite数据库进行数据存储,使用 SQLAlchemy 库进行数据库匹配,掌握了 ORM 知识。
6.2 展望
本系统的不足之处在于,系统并未进行工作环境的部署并进行上线,在未来的开发中,需要系统的部署于上线等知识,将系统进行部署上线。