摘要
博客是典型的CMS(Content Management System姓迅,內容管理系統(tǒng)),通常由兩部分組成:一部分是博客前臺快耿,用來展示開放給所有用戶的博客內容盏袄;另一部分是博客后臺,這部分內容僅開放給博客管理員葱她,用來對博客資源進行添加撩扒、修改和刪除等操作。本文通過分析個人博客的功能需求吨些,采用 python 的web 框架flask實現(xiàn)一個個人博客系統(tǒng)搓谆。
1、引言
本文旨在開發(fā)一個個人博客系統(tǒng)豪墅,采用的程序設計語言是python泉手,web 開發(fā)框架是flask,數(shù)據(jù)庫是 SQLite偶器。
Python是一種跨平臺的計算機程序設計語言斩萌。是一個高層次的結合了解釋性、編譯性状囱、互動性和面向對象的腳本語言术裸。最初被設計用于編寫自動化腳本(shell),隨著版本的不斷更新和語言新功能的添加亭枷,越多被用于獨立的、大型項目的開發(fā)搀崭。
Flask是一個輕量級的可定制框架叨粘,使用Python語言編寫,較其他同類型框架更為靈活瘤睹、輕便升敲、安全且容易上手。它可以很好地結合MVC模式進行開發(fā)轰传,開發(fā)人員分工合作驴党,小型團隊在短時間內就可以完成功能豐富的中小型網站或Web服務的實現(xiàn)。另外获茬,F(xiàn)lask還有很強的定制性港庄,用戶可以根據(jù)自己的需求來添加相應的功能倔既,在保持核心功能簡單的同時實現(xiàn)功能的豐富與擴展,其強大的插件庫可以讓用戶實現(xiàn)個性化的網站定制鹏氧,開發(fā)出功能強大的網站渤涌。
SQLite,是一款輕型的數(shù)據(jù)庫把还,是關系型數(shù)據(jù)庫管理系統(tǒng)实蓬,在 python 中內置了 SQLite庫。本文采用 SQLite 進行快速開發(fā)與測試吊履。
本文結構如下:
第一章安皱, 引言。介紹本文目的艇炎,采用技術介紹和文章結構酌伊。
第二章, 需求分析冕臭,詳細分析了個人博客系統(tǒng)的功能需求腺晾。
第三章, 數(shù)據(jù)庫分析與設計辜贵。詳細介紹了個人博客系統(tǒng)的數(shù)據(jù)庫表設計與實現(xiàn)悯蝉。
第四章, 詳細設計托慨。介紹了個人模塊系統(tǒng)的項目結構鼻由、功能模塊及其代碼實現(xiàn)。
第五章厚棵, 實驗結果蕉世。介紹了個人博客系統(tǒng)的實現(xiàn)效果。
第六章婆硬, 總結和展望狠轻。介紹對項目開發(fā)的經驗總結以及系統(tǒng)的不足與完善目標。
2彬犯、需求分析
2.1 功能需求
個人博客系統(tǒng)主要分為三個模塊向楼,分別為:博客前臺、博客后臺谐区、用戶認證湖蜕。
2.1.1 博客前臺
博客前臺展示博客文章信息,功能如下:
- 文章列表(主頁):網站主頁顯示-- 博客文章列表宋列。
- 文章詳情頁面:頁面顯示博客文章的詳情昭抒。
- 評論列表:在博客文章詳情頁面顯示評論列表。
- 發(fā)表評論:在博客文章詳情頁面對文章發(fā)表評論。
- 回復評論:在評論列表中回復評論灭返。
2.1.2 博客后臺
博客后臺為博客管理員對博客進行管理盗迟,功能如下:
- 文章管理功能,創(chuàng)建文章婆殿,更新文章诈乒,刪除文章。
- 管理分類功能婆芦,創(chuàng)建分類绒极,更新分類倍宾,刪除分類妄讯。
- 管理評論功能氢伟,關閉文章評論,刪除文章評論或粮,審核評論导饲,評論篩選。
博客資料設置氯材,置博客信息渣锦。
2.1.3用戶認證
創(chuàng)建管理源賬戶
用戶登陸功能
2.2 功能結構圖
3、數(shù)據(jù)庫設計
3.1 數(shù)據(jù)庫表設計
3.1.1 管理員
字段名 | 類型 | 大小 | 備注 |
---|---|---|---|
id | 是 | 是 | |
username | 是 | 是 | |
password | 否 | 否 | |
blog_title | 是 | 否 | |
blog_subtitle | 否 | 否 |
3.2 E-R 圖
4氢哮、設計實現(xiàn)
4.1 項目結構
blog/
blueprint/ 功能模塊
- __init__.py
- blog.py 博客前臺
- auth.py 用戶認證
- admin.py 博客后臺
templates/ 頁面模板
- admin/ 后臺頁面
- auth/ 認證頁面
- blog/ 前臺頁面
- base.html
- macros.html
static/ 靜態(tài)資源
forms.py 表單
models.py 數(shù)據(jù)模型
email.py 郵箱驗證
utils.py 輔助
fakes.py 虛擬數(shù)據(jù)
extensions.py 擴展
4.2 數(shù)據(jù)模型實現(xiàn)
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 功能實現(xiàn)
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 學習總結
在開發(fā)個人博客系統(tǒng)的過程中蝎困,遇到了許多困難,也學習到了許多新的知識倍啥。遇到的困難主要是陌生技術/框架的掌握上,在開發(fā)系統(tǒng)的過程中澎埠,需要引入新的技術/框架虽缕,由于新技術/框架的原理或者知識領域相對陌生,在掌握的過程中存在一些困難蒲稳。在解決這些困難的工程中氮趋,一并掌握了這些新技術/框架的原理和領域知識伍派。
在開發(fā)本系統(tǒng)的過程中,掌握了許多知識剩胁。本系統(tǒng)采用 flask web 開發(fā)框架诉植,由此學習了web 開發(fā)技術,http 原理昵观,B/S架構模式等知識晾腔。系統(tǒng)還使用 fakes 庫產生虛擬數(shù)據(jù),進行數(shù)據(jù)填充啊犬,學習掌握產生虛擬數(shù)據(jù)的方法灼擂。系統(tǒng)使用SQLite數(shù)據(jù)庫進行數(shù)據(jù)存儲,使用 SQLAlchemy 庫進行數(shù)據(jù)庫匹配觉至,掌握了 ORM 知識剔应。
6.2 展望
本系統(tǒng)的不足之處在于,系統(tǒng)并未進行工作環(huán)境的部署并進行上線语御,在未來的開發(fā)中峻贮,需要系統(tǒng)的部署于上線等知識,將系統(tǒng)進行部署上線应闯。