基于Python Flask构建博客系统并实现内网穿透访问
本文详细介绍如何利用轻量级Python框架Flask快速搭建个人博客系统,涵盖用户注册登录、文章发布管理、分类及分页展示等核心功能模块。同时,针对本地开发环境无法被公网访问的问题,提供了使用花生壳工具进行内网穿透的具体操作步骤,帮助开发者低成本实现本地项目的公网部署与访问。
前言
Flask是一款基于Python开发的轻量级Web框架,相较于其他同类框架,其优势在于极高的灵活性与轻量化。该框架具备强大的可定制性,允许开发者根据具体需求扩展功能,并拥有丰富的插件生态,这也是Flask在Python开发领域持续保持热门地位的关键原因。本文将指导读者使用Flask框架从零开始构建一个个人博客网站,并演示如何通过内网穿透技术使本地项目具备公网访问能力。
🚀首先来看看我们开发的博客Web项目的一些展示


该博客项目主要涵盖以下核心功能模块:用户注册与登录、首页文章列表展示、文章详情页展示、文章发布功能、文章分类添加、文章分类管理、用户信息管理、数据库初始化以及程序启动入口封装。
🚀下面我们对各个模块的代码进行编写
1.个人的注册与登录模块
此模块主要实现用户注册功能,系统会校验用户输入的两次密码是否一致,校验通过后会将用户信息写入数据库。

from flask import render_template, redirect, url_for, request, flash, session
from front_back import front
from modles.dbmodels import User, db
import hashlib
from utils import login_check
@front.route('/login',methods=['GET','POST'])
def login():
if request.method=='GET':
return render_template('login.html')
elif request.method=='POST':
username=request.form.get('username')
password=request.form.get('password')
user=User.query.filter_by(username=username,password=password).first()
print(user)
if user:
session['user']=username
print(session['user'])
flash('登录成功')
return redirect(url_for('front.index'))
else:
flash('登录失败')
return redirect(url_for('front.login'))
@front.route('/register',methods=['GET','POST'])
def register():
# 如果是get请求的话就返回页面,post请求的话就接收表单数据
if request.method == 'GET':
return render_template("register.html")
elif request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
check_password = request.form.get('check_password')
if username and password and password == check_password:
md5 = hashlib.md5()
md5.update(password.encode('utf-8'))
user = User()
user.username = username
# 使用hashlib加密密码再存入数据库,拿到md5.hexdigest()加密后的密码
user.password = md5.hexdigest()
user.password=password
print(username,password)
try:
db.session.add(user)
db.session.commit()
flash('注册成功,欢迎访问我的个人博客!')
return redirect(url_for('front.register'))
except Exception:
flash('注册失败,请检查密码后重新注册')
return redirect(url_for('front.register'))
else:
flash('注册失败')
return redirect(url_for('front.register'))
2.首页文章展示模块
该模块集成了分页显示功能。当文章数量超过单页显示上限时,系统将通过分页机制进行展示,并利用Bootstrap框架提供的分页导航组件实现前端交互。使用Bootstrap进行前端开发,即使开发者前端基础薄弱,也能快速构建出美观的页面效果。

@front.route('/index')
@front.route('/')
# @login_required
def index():
page=int(request.args.get('page',default=1)) #找到传入的?page=? 参数,没有的话默认就是1,因为传回来的是字符串,所以需要转化成int
#pre_page=? 这个是设置每一页最多显示几条数据
paginate=Article.query.order_by(Article.create_time.desc()).paginate(page=page,per_page=5)
article=paginate.items
groups=ArticleGroup.query.all() #拿到模型所有的数据
return render_template("index.html",groups=groups,article=article,paginate=paginate)
3.文章详情展示模块
此模块负责获取指定文章的完整数据,并通过文章ID进行精准匹配与展示。

@front.route('/article_detail/<int:article_id>')
# @login_required
def article_detail(article_id):
article=Article.query.get(article_id)
groups=ArticleGroup.query.all() #拿到模型所有的数据
return render_template("article_detail.html",groups=groups,article=article)
4.文章发布模块
该模块集成了Markdown格式的文章编辑功能。用户可依据Markdown语法撰写并发布文章,同时界面右侧提供实时语法预览窗口,方便用户直观查看文章最终呈现效果。

@front.route('/add_article',methods=['GET','POST'])
# @login_required
def add_article():
if request.method=='GET':
groups=ArticleGroup.query.all() #拿到模型所有的数据
return render_template("add_article.html",groups=groups)
elif request.method=='POST':
title=request.form.get('title')
content=request.form.get('content')
gid=request.form.get('gid')
user=User.query.filter_by(username=session.get('user')).first()
uid=user.id
# 获取当前时间,从datetime这个库里面
create_time=datetime.datetime.now()
article=Article()
article.title=title
article.content=content
article.gid=gid
article.uid=uid
article.create_time=create_time
print(user,title,content,gid,uid,create_time)
try:
db.session.add(article)
db.session.commit()
flash('添加%s成功' % title)
return redirect(url_for('front.add_article'))
except Exception:
flash('添加%s失败' % title)
return redirect(url_for('front.add_article'))
5.文章添加分类模块
在此模块中,用户可以自定义输入分类名称,并选择该分类在界面中展示的颜色标识,相关数据将同步保存至数据库。

@front.route("/add_group",methods=['GET','POST'])
def add_group():
if request.method=='GET':
groups = ArticleGroup.query.all()
colors=['default','primary','success','into','warning','danger']
return render_template('add_group.html',colors=colors,groups=groups)
elif request.method=='POST':
name=request.form.get('name')
color=request.form.get('color')
group=ArticleGroup()
group.name=name
group.color=color
try:
db.session.add(group)
db.session.commit()
flash("添加分组成功")
return redirect(url_for('front.manage'))
except Exception:
flash("添加失败")
return redirect(url_for('front.manage'))
6.文章分类管理模块
该模块主要用于对已创建的分类及其关联颜色进行编辑和删除操作,实现分类数据的动态管理。

@front.route("/article_group_manage")
def article_group_manage():
groups = ArticleGroup.query.all()
return render_template('article_group_mange.html',groups=groups)
@front.route('/edit_group/<int:gid>',methods=['GET','POST'])
def edit_group(gid):
if request.method=='GET':
groups=ArticleGroup.query.all()
#找到通过id找到分组
group=ArticleGroup.query.get(gid)
colors = ['default', 'primary', 'success', 'into', 'warning', 'danger']
return render_template('edit_group.html',group=group,colors=colors,groups=groups)
elif request.method=='POST':
name=request.form.get("name")
color=request.form.get("color")
group=ArticleGroup.query.get(gid)
group.name=name
group.color=color
try:
db.session.add(group)
db.session.commit()
flash("修改成功")
return redirect(url_for("front.article_group_manage"))
except Exception:
flash("修改失败")
return redirect(url_for("front.article_group_mange"))
# 删除的 视图函数
@front.route('/delete_group/<int:gid>')
def delete_group(gid):
group=ArticleGroup.query.get(gid)
try:
db.session.delete(group)
db.session.commit()
flash('删除%s成功' % group.name)
return redirect(url_for("front.article_group_manage"))
except Exception:
flash('删除%s失败' % group.name)
return redirect(url_for("front.article_group_manage"))
7.文章管理模块
此模块提供对已发布文章的编辑与管理功能。用户若需对旧文章进行修订,可在此模块中修改内容,或执行删除、重新发布等操作。

@front.route('/edit_article/<int:article_id>',methods=['GET','POST'])
def edit_article(article_id):
if request.method=='GET':
# 拿到文章内容
article=Article.query.get(article_id)
groups=ArticleGroup.query.all()
return render_template('edit_article.html',groups=groups,article=article)
elif request.method=='POST':
title=request.form.get("title")
content=request.form.get("content")
gid=request.form.get("gid")
update_time=datetime.datetime.now()
article=Article.query.get(article_id)
article.title=title
article.content=content
print(content)
article.gid=gid
article.update_time=update_time
try:
db.session.commit()
return redirect(url_for("front.article_manage"))
except Exception:
flash("修改%s失败" % title)
return redirect(url_for("front.article_manage"))
@front.route('/delete_article/<int:article_id>')
def delete_article(article_id):
article=Article.query.get(article_id)
try:
db.session.delete(article)
db.session.commit()
flash("删除文章%s成功"%article.title)
return redirect(url_for("front.article_manage"))
except Exception:
flash("删除文章%s失败"%article.title)
return redirect(url_for("front.article_manage"))
8.用户个人信息注销模块
通过此模块,用户可以一键注销当前登录状态,并自动跳转回登录页面。
# 注销登录,在base写上
@front.route('/logout')
def logout():
session.clear()
flash("注销登录成功")
return redirect(url_for('front.login'))
9.信息管理模块
上述所有模块产生的数据均需存储至MySQL数据库。首先需在本地MySQL中创建名为blog的数据库,随后运行Web项目。该模块会自动将数据模型与数据库表进行映射并创建相应表结构及字段类型,从而避免手动创建数据表的繁琐步骤。
login_manager = LoginManager()
db=SQLAlchemy() #实例化sqlalchemy对象
class User(db.Model,UserMixin):
# __tablename__='login_register'
id = Column(db.Integer,autoincrement=True,primary_key=True)
#autoincrement自增长
username=Column(db.String(50),nullable=False)
password=Column(db.String(128),nullable=True)
# 没有这个的话,使用{{users}}显示的就是一个对象
def __repr__(self):
return self.username
def get_id(self):
return True
class Article(db.Model):
__tablename__='article'
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
title = db.Column(db.String(50), nullable=False,unique=True)
content=db.Column(db.String(512),nullable=True)
uid=db.Column(db.Integer,db.ForeignKey('user.id'))
gid=db.Column(db.Integer,db.ForeignKey('article_group.id'))
create_time=db.Column(db.DateTime)
update_time=db.Column(db.DateTime)
#下面相当于做一个联表查询。
users=db.relationship('User',backref=db.backref('articles'))
groups=db.relationship('ArticleGroup',backref=db.backref('articles'))
def __repr__(self):
return '<Article %s>'%self.title
class ArticleGroup(db.Model):
__tablename__='article_group'
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
name = db.Column(db.String(50), nullable=False,unique=True)
color= db.Column(db.String(50), nullable=False)
def __repr__(self):
return '<ArticleGroup %s>'% self.name
@login_manager.user_loader
def get_user(user_id):
#对主键的查询是没有必要使用filler_by的
user = db.session.query(User).get(user_id)
return user
10.程序启动模块
为了使Flask应用的启动入口更加简洁,本模块对启动代码进行了封装处理。
def create_app():
app=Flask(__name__)
app.config.from_object('config')
register_blueprint(app)
db.init_app(app)
login_manager.init_app(app)
login_manager.login_view="front.login"
login_manager.login_message_category='请先登录或注册'
db.create_all(app=app)
return app
def register_blueprint(app):
from front_back import front
app.register_blueprint(front)
应用程序主类

from current import create_app
app=create_app()
if __name__ == '__main__':
app.run(host='0.0.0.0',debug=True,port=83)
至此,博客项目的核心模块代码编写已完成。实际上,开发者可根据实际需求继续扩展更多功能,这也是Flask框架极具特色的优势之一。需要说明的是,由于前端代码篇幅较长,此处不予展示,如有需要获取完整代码的读者,可联系作者获取。
11.内网穿透模块
此模块对于部分读者可能较为陌生,此处通过一个具体案例进行说明。
假设我们需要将上述开发完成的项目部署并供所有人访问,常规思路是使用云服务器。然而,服务器成本较高且部署流程复杂。是否存在一种方式能将本地服务映射至公网供访问?答案即是内网穿透技术。
此处推荐一款便捷的内网穿透工具:花生壳。用户可直接搜索并下载该工具。
下载完成后,只需将本机IP地址填入工具中,系统即可自动生成一个域名,从而实现公网可访问,效果如下图所示。

随后在浏览器中测试访问链接,若成功访问,则表明映射配置无误。

12.总结
至此,关于使用Python Flask开发博客项目并实现内网穿透的教程已介绍完毕。如需了解更多Flask开发博客及内网穿透相关内容,欢迎查阅本站往期文章或继续浏览后续内容,感谢大家的支持!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









