当前位置: 首页 > news >正文

Python实例题:基于 Flask 的博客系统

目录

Python实例题

题目

要求:

解题思路:

代码实现:

1. base.html

2. index.html

3. post.html

4. create_post.html

5. login.html

6. register.html

Python实例题

题目

基于 Flask 的博客系统

要求

  • 使用 Flask 框架构建一个简单的博客系统。
  • 实现用户认证(注册、登录、注销)。
  • 支持博客文章的创建、编辑、删除和查看。
  • 使用 SQLite 数据库存储用户和文章数据。
  • 添加评论功能,允许已登录用户对文章发表评论。
  • 实现简单的权限控制(如只有文章作者才能编辑 / 删除文章)。
  • 添加分页功能,美化界面(使用 Bootstrap)。

解题思路

  • 使用 Flask 蓝图组织代码结构。
  • 通过 Flask-Login 处理用户认证。
  • 使用 Flask-SQLAlchemy 管理数据库操作。
  • 结合 WTForms 实现表单验证。
  • 使用 Bootstrap 美化前端界面。

代码实现

from flask import Flask, render_template, request, redirect, url_for, flash, Blueprint
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
import os# 初始化 Flask 应用
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key-here'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(app.root_path, 'blog.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False# 初始化数据库
db = SQLAlchemy(app)# 初始化 Flask-Login
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'auth.login'# 数据模型
class User(UserMixin, db.Model):id = db.Column(db.Integer, primary_key=True)username = db.Column(db.String(80), unique=True, nullable=False)password_hash = db.Column(db.String(120), nullable=False)posts = db.relationship('Post', backref='author', lazy=True)comments = db.relationship('Comment', backref='author', lazy=True)def set_password(self, password):self.password_hash = generate_password_hash(password)def check_password(self, password):return check_password_hash(self.password_hash, password)class Post(db.Model):id = db.Column(db.Integer, primary_key=True)title = db.Column(db.String(100), nullable=False)content = db.Column(db.Text, nullable=False)date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)comments = db.relationship('Comment', backref='post', lazy=True)class Comment(db.Model):id = db.Column(db.Integer, primary_key=True)content = db.Column(db.Text, nullable=False)date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)# 用户加载回调
@login_manager.user_loader
def load_user(user_id):return User.query.get(int(user_id))# 认证蓝图
auth = Blueprint('auth', __name__)@auth.route('/register', methods=['GET', 'POST'])
def register():if request.method == 'POST':username = request.form['username']password = request.form['password']if User.query.filter_by(username=username).first():flash('用户名已存在', 'error')return redirect(url_for('auth.register'))user = User(username=username)user.set_password(password)db.session.add(user)db.session.commit()flash('注册成功,请登录', 'success')return redirect(url_for('auth.login'))return render_template('register.html')@auth.route('/login', methods=['GET', 'POST'])
def login():if request.method == 'POST':username = request.form['username']password = request.form['password']user = User.query.filter_by(username=username).first()if user and user.check_password(password):login_user(user)flash('登录成功', 'success')return redirect(url_for('main.index'))else:flash('用户名或密码错误', 'error')return render_template('login.html')@auth.route('/logout')
@login_required
def logout():logout_user()flash('已注销', 'success')return redirect(url_for('main.index'))# 主蓝图
main = Blueprint('main', __name__)@main.route('/')
def index():page = request.args.get('page', 1, type=int)posts = Post.query.order_by(Post.date_posted.desc()).paginate(page=page, per_page=5)return render_template('index.html', posts=posts)@main.route('/post/new', methods=['GET', 'POST'])
@login_required
def new_post():if request.method == 'POST':title = request.form['title']content = request.form['content']post = Post(title=title, content=content, author=current_user)db.session.add(post)db.session.commit()flash('文章发布成功', 'success')return redirect(url_for('main.index'))return render_template('create_post.html', title='新文章')@main.route('/post/<int:post_id>')
def post(post_id):post = Post.query.get_or_404(post_id)return render_template('post.html', post=post)@main.route('/post/<int:post_id>/update', methods=['GET', 'POST'])
@login_required
def update_post(post_id):post = Post.query.get_or_404(post_id)if post.author != current_user:flash('你无权编辑此文章', 'error')return redirect(url_for('main.post', post_id=post.id))if request.method == 'POST':post.title = request.form['title']post.content = request.form['content']db.session.commit()flash('文章已更新', 'success')return redirect(url_for('main.post', post_id=post.id))return render_template('create_post.html', title='更新文章', post=post)@main.route('/post/<int:post_id>/delete', methods=['POST'])
@login_required
def delete_post(post_id):post = Post.query.get_or_404(post_id)if post.author != current_user:flash('你无权删除此文章', 'error')return redirect(url_for('main.post', post_id=post.id))db.session.delete(post)db.session.commit()flash('文章已删除', 'success')return redirect(url_for('main.index'))@main.route('/post/<int:post_id>/comment', methods=['POST'])
@login_required
def add_comment(post_id):post = Post.query.get_or_404(post_id)content = request.form['content']comment = Comment(content=content, author=current_user, post=post)db.session.add(comment)db.session.commit()flash('评论已提交', 'success')return redirect(url_for('main.post', post_id=post_id))# 注册蓝图
app.register_blueprint(main)
app.register_blueprint(auth)# 创建数据库表
with app.app_context():db.create_all()if __name__ == '__main__':app.run(debug=True)

对应的 HTML 模板文件(需要放在 templates 文件夹中):

1. base.html

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Flask博客</title><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css">
</head>
<body><nav class="navbar navbar-expand-lg navbar-light bg-light"><div class="container"><a class="navbar-brand" href="{{ url_for('main.index') }}">Flask博客</a><div class="collapse navbar-collapse" id="navbarNav"><ul class="navbar-nav me-auto"><li class="nav-item"><a class="nav-link" href="{{ url_for('main.index') }}">首页</a></li></ul><ul class="navbar-nav">{% if current_user.is_authenticated %}<li class="nav-item"><a class="nav-link" href="{{ url_for('main.new_post') }}">新文章</a></li><li class="nav-item"><a class="nav-link" href="{{ url_for('auth.logout') }}">注销 ({{ current_user.username }})</a></li>{% else %}<li class="nav-item"><a class="nav-link" href="{{ url_for('auth.login') }}">登录</a></li><li class="nav-item"><a class="nav-link" href="{{ url_for('auth.register') }}">注册</a></li>{% endif %}</ul></div></div></nav><div class="container mt-4">{% with messages = get_flashed_messages(with_categories=true) %}{% if messages %}{% for category, message in messages %}<div class="alert alert-{{ category }}">{{ message }}</div>{% endfor %}{% endif %}{% endwith %}{% block content %}{% endblock %}</div><script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

2. index.html

{% extends "base.html" %}{% block content %}<h1 class="mb-4">博客文章</h1>{% for post in posts.items %}<div class="card mb-4"><div class="card-body"><h2 class="card-title">{{ post.title }}</h2><p class="card-text">{{ post.content[:200] }}{% if post.content|length > 200 %}...{% endif %}</p><a href="{{ url_for('main.post', post_id=post.id) }}" class="btn btn-primary"></a></div><div class="card-footer text-muted">发布于 {{ post.date_posted.strftime('%Y-%m-%d') }} by {{ post.author.username }}</div></div>{% endfor %}<!-- 分页导航 --><nav aria-label="Page navigation"><ul class="pagination justify-content-center">{% if posts.has_prev %}<li class="page-item"><a class="page-link" href="{{ url_for('main.index', page=posts.prev_num) }}">上一页</a></li>{% else %}<li class="page-item disabled"><span class="page-link">上一页</span></li>{% endif %}{% for page_num in posts.iter_pages(left_edge=1, right_edge=1, left_current=1, right_current=2) %}{% if page_num %}{% if posts.page == page_num %}<li class="page-item active"><span class="page-link">{{ page_num }}</span></li>{% else %}<li class="page-item"><a class="page-link" href="{{ url_for('main.index', page=page_num) }}">{{ page_num }}</a></li>{% endif %}{% else %}<li class="page-item disabled"><span class="page-link">...</span></li>{% endif %}{% endfor %}{% if posts.has_next %}<li class="page-item"><a class="page-link" href="{{ url_for('main.index', page=posts.next_num) }}">下一页</a></li>{% else %}<li class="page-item disabled"><span class="page-link">下一页</span></li>{% endif %}</ul></nav>
{% endblock %}

3. post.html

{% extends "base.html" %}{% block content %}<div class="card mb-4"><div class="card-body"><h2 class="card-title">{{ post.title }}</h2><p class="card-text">{{ post.content }}</p></div><div class="card-footer text-muted">发布于 {{ post.date_posted.strftime('%Y-%m-%d %H:%M') }} by {{ post.author.username }}{% if current_user.is_authenticated and current_user == post.author %}<div class="float-right"><a href="{{ url_for('main.update_post', post_id=post.id) }}" class="btn btn-sm btn-outline-secondary">编辑</a><form action="{{ url_for('main.delete_post', post_id=post.id) }}" method="POST" class="d-inline"><button type="submit" class="btn btn-sm btn-outline-danger" onclick="return confirm('确定要删除这篇文章吗?')">删除</button></form></div>{% endif %}</div></div><!-- 评论区 --><h3 class="mb-4">评论 ({{ post.comments|length }})</h3>{% for comment in post.comments %}<div class="card mb-3"><div class="card-body"><p class="card-text">{{ comment.content }}</p><div class="text-muted"><small>由 {{ comment.author.username }} 发布于 {{ comment.date_posted.strftime('%Y-%m-%d %H:%M') }}</small></div></div></div>{% endfor %}<!-- 添加评论表单 -->{% if current_user.is_authenticated %}<div class="card mb-4"><div class="card-header">添加评论</div><div class="card-body"><form method="POST" action="{{ url_for('main.add_comment', post_id=post.id) }}"><div class="form-group"><textarea class="form-control" name="content" rows="3" required></textarea></div><button type="submit" class="btn btn-primary mt-3">提交评论</button></form></div></div>{% else %}<div class="alert alert-info"><a href="{{ url_for('auth.login') }}">登录</a> 后可发表评论</div>{% endif %}
{% endblock %}

4. create_post.html

{% extends "base.html" %}{% block content %}<h1>{{ title }}</h1><form method="POST"><div class="form-group"><label for="title">标题</label><input type="text" class="form-control" id="title" name="title" value="{{ post.title if post else '' }}" required></div><div class="form-group mt-3"><label for="content">内容</label><textarea class="form-control" id="content" name="content" rows="10" required>{{ post.content if post else '' }}</textarea></div><button type="submit" class="btn btn-primary mt-3">提交</button></form>
{% endblock %}

5. login.html

{% extends "base.html" %}{% block content %}<h1>登录</h1><form method="POST"><div class="form-group"><label for="username">用户名</label><input type="text" class="form-control" id="username" name="username" required></div><div class="form-group mt-3"><label for="password">密码</label><input type="password" class="form-control" id="password" name="password" required></div><button type="submit" class="btn btn-primary mt-3">登录</button></form><p class="mt-3">还没有账号? <a href="{{ url_for('auth.register') }}">注册</a></p>
{% endblock %}

6. register.html

{% extends "base.html" %}{% block content %}<h1>注册</h1><form method="POST"><div class="form-group"><label for="username">用户名</label><input type="text" class="form-control" id="username" name="username" required></div><div class="form-group mt-3"><label for="password">密码</label><input type="password" class="form-control" id="password" name="password" required></div><button type="submit" class="btn btn-primary mt-3">注册</button></form><p class="mt-3">已有账号? <a href="{{ url_for('auth.login') }}">登录</a></p>
{% endblock %}

相关文章:

  • 人工智能编程三大核心流程详解--机器学习、神经网络、NLP自然语言处理
  • K8s: Kubernetes
  • 权威认证!华宇TAS应用中间件荣获CCRC“中间件产品安全认证”
  • Beam2.61.0版本消费kafka重复问题排查
  • SQL SERVER存储过程
  • SQL重置自增
  • Solidity学习 - 认识Solidity合约结构
  • Windows命令连接符的安全风险分析与防御策略
  • [附源码+数据库+毕业论文+开题报告]基于Spring+MyBatis+MySQL+Maven+jsp实现的宠物领养管理系统,推荐!
  • 无人机关键算法分析 ( MPU6050 ,PID,滤波,四元数,欧拉角,IMU 姿态解算)
  • vue3中使用vue-grid-layout来实现可拖动的仪表盘面板
  • 深度学习在智能物流中的创新应用与未来趋势
  • 在统信UOS(Linux)中构建SQLite3桌面应用笔记
  • C++之string类的实现代码及其详解(上)
  • 0 数学习题本
  • 【stm32】HAL库开发——Cube配置基本定时器
  • Llama 3 + Qwen2双模型实战:单张3090构建企业级多模态知识库(2025精解版)
  • 关于 ARM64 汇编:调用流程与栈帧结构解析
  • Jenkins与Kubernetes深度整合实践
  • GitLab 18.1 高级 SAST 已支持 PHP,可升级体验!