12.2 核心功能开发
Flask核心功能开发教程:用户模块、文章模块、评论模块与页面开发
本教程详细讲解如何使用Flask框架实现核心功能,包括用户模块(注册、登录、个人信息管理)、文章模块(发布、编辑、删除、详情展示)、评论模块(提交、列表展示、权限控制)以及首页与分类页开发(分页、筛选)。内容适合新手,涵盖代码示例和步骤解释。
Flask核心功能开发教程
介绍
Flask是一个轻量级的Python Web框架,易于扩展,适合快速开发Web应用。本教程将详细介绍如何使用Flask实现一个博客应用的核心功能,包括用户管理、文章操作、评论系统和页面开发。我们将从项目设置开始,逐步实现每个模块,确保对初学者友好。
在开始前,请确保已安装Python和Flask。可以使用以下命令安装Flask:
pip install flask
此外,我们还将使用Flask扩展如Flask-SQLAlchemy(用于数据库)、Flask-Login(用于用户认证)和Flask-WTF(用于表单处理)。
用户模块
用户模块是Web应用的基础,包括注册、登录和个人信息管理功能。
1. 注册功能
注册功能允许用户创建新账户。我们将使用Flask-SQLAlchemy来定义用户模型和存储数据。
首先,设置Flask应用和数据库:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt # 用于密码哈希
from flask_login import LoginManager # 用于用户认证
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key' # 设置密钥
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db' # 使用SQLite数据库
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login' # 设置登录视图
定义User模型:
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password_hash = db.Column(db.String(60), nullable=False) # 存储哈希密码
def __repr__(self):
return f"User('{self.username}', '{self.email}')"
创建注册表单(使用Flask-WTF):
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, Email, EqualTo
class RegistrationForm(FlaskForm):
username = StringField('用户名', validators=[DataRequired(), Length(min=2, max=20)])
email = StringField('邮箱', validators=[DataRequired(), Email()])
password = PasswordField('密码', validators=[DataRequired()])
confirm_password = PasswordField('确认密码', validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('注册')
处理注册逻辑的路由:
from flask import render_template, flash, redirect, url_for
from forms import RegistrationForm
from models import User, db
from flask_bcrypt import generate_password_hash
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
# 检查用户名和邮箱是否已存在
existing_user = User.query.filter_by(username=form.username.data).first()
existing_email = User.query.filter_by(email=form.email.data).first()
if existing_user:
flash('用户名已存在,请选择其他用户名', 'danger')
elif existing_email:
flash('邮箱已注册,请使用其他邮箱', 'danger')
else:
# 哈希密码并创建新用户
hashed_password = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
user = User(username=form.username.data, email=form.email.data, password_hash=hashed_password)
db.session.add(user)
db.session.commit()
flash('注册成功!请登录。', 'success')
return redirect(url_for('login'))
return render_template('register.html', title='注册', form=form)
在模板中(register.html),使用表单字段渲染页面。
2. 登录功能
登录功能验证用户凭据并管理会话。
定义登录表单:
class LoginForm(FlaskForm):
username = StringField('用户名', validators=[DataRequired()])
password = PasswordField('密码', validators=[DataRequired()])
submit = SubmitField('登录')
处理登录逻辑的路由:
from flask_login import login_user, current_user
@app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated: # 如果用户已登录,重定向到首页
return redirect(url_for('home'))
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user and bcrypt.check_password_hash(user.password_hash, form.password.data):
login_user(user) # 登录用户
flash('登录成功!', 'success')
return redirect(url_for('home'))
else:
flash('登录失败,请检查用户名或密码', 'danger')
return render_template('login.html', title='登录', form=form)
使用Flask-Login管理用户会话。在models.py中,添加以下方法到User类:
from flask_login import UserMixin
class User(db.Model, UserMixin): # 继承UserMixin以提供默认方法
# 同上定义
pass
3. 个人信息管理
允许登录用户编辑个人信息。
定义编辑表单:
class UpdateAccountForm(FlaskForm):
username = StringField('用户名', validators=[DataRequired(), Length(min=2, max=20)])
email = StringField('邮箱', validators=[DataRequired(), Email()])
submit = SubmitField('更新')
处理更新逻辑的路由:
from flask_login import login_required
@app.route('/account', methods=['GET', 'POST'])
@login_required # 需要登录访问
def account():
form = UpdateAccountForm()
if form.validate_on_submit():
current_user.username = form.username.data
current_user.email = form.email.data
db.session.commit()
flash('个人信息已更新!', 'success')
return redirect(url_for('account'))
elif request.method == 'GET':
form.username.data = current_user.username
form.email.data = current_user.email
return render_template('account.html', title='个人账户', form=form)
文章模块
文章模块处理文章的发布、编辑、删除和详情展示。
1. 发布文章
定义Article模型:
class Article(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) # 关联用户
author = db.relationship('User', backref=db.backref('articles', lazy=True)) # 定义关系
创建发布表单:
class ArticleForm(FlaskForm):
title = StringField('标题', validators=[DataRequired(), Length(max=100)])
content = TextAreaField('内容', validators=[DataRequired()])
submit = SubmitField('发布')
处理发布逻辑的路由:
from datetime import datetime
@app.route('/article/new', methods=['GET', 'POST'])
@login_required
def new_article():
form = ArticleForm()
if form.validate_on_submit():
article = Article(title=form.title.data, content=form.content.data, author=current_user)
db.session.add(article)
db.session.commit()
flash('文章已发布!', 'success')
return redirect(url_for('home'))
return render_template('create_article.html', title='发布文章', form=form)
2. 编辑文章
处理编辑逻辑的路由:
@app.route('/article/<int:article_id>/update', methods=['GET', 'POST'])
@login_required
def update_article(article_id):
article = Article.query.get_or_404(article_id)
if article.author != current_user: # 权限检查:只有作者可以编辑
abort(403) # 返回禁止访问错误
form = ArticleForm()
if form.validate_on_submit():
article.title = form.title.data
article.content = form.content.data
db.session.commit()
flash('文章已更新!', 'success')
return redirect(url_for('article_detail', article_id=article.id))
elif request.method == 'GET':
form.title.data = article.title
form.content.data = article.content
return render_template('update_article.html', title='编辑文章', form=form, article=article)
3. 删除文章
处理删除逻辑的路由:
@app.route('/article/<int:article_id>/delete', methods=['POST'])
@login_required
def delete_article(article_id):
article = Article.query.get_or_404(article_id)
if article.author != current_user:
abort(403)
db.session.delete(article)
db.session.commit()
flash('文章已删除!', 'success')
return redirect(url_for('home'))
4. 文章详情展示
处理详情展示的路由:
@app.route('/article/<int:article_id>')
def article_detail(article_id):
article = Article.query.get_or_404(article_id)
return render_template('article_detail.html', title=article.title, article=article)
在模板中显示文章内容和作者信息。
评论模块
评论模块允许用户对文章进行评论,并管理权限。
1. 提交评论
定义Comment模型:
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)
article_id = db.Column(db.Integer, db.ForeignKey('article.id'), nullable=False)
author = db.relationship('User', backref=db.backref('comments', lazy=True))
article = db.relationship('Article', backref=db.backref('comments', lazy=True))
创建评论表单:
class CommentForm(FlaskForm):
content = TextAreaField('评论内容', validators=[DataRequired()])
submit = SubmitField('提交评论')
处理提交逻辑的路由(在文章详情页):
@app.route('/article/<int:article_id>', methods=['GET', 'POST'])
def article_detail(article_id):
article = Article.query.get_or_404(article_id)
form = CommentForm()
if form.validate_on_submit():
if not current_user.is_authenticated: # 权限控制:用户必须登录
flash('请登录后评论', 'warning')
return redirect(url_for('login'))
comment = Comment(content=form.content.data, author=current_user, article=article)
db.session.add(comment)
db.session.commit()
flash('评论已提交!', 'success')
return redirect(url_for('article_detail', article_id=article.id))
comments = Comment.query.filter_by(article_id=article.id).order_by(Comment.date_posted.desc()).all() # 获取评论列表
return render_template('article_detail.html', title=article.title, article=article, form=form, comments=comments)
2. 评论列表展示
在文章详情模板中,循环显示comments列表。
3. 权限控制
限制删除评论权限:
@app.route('/comment/<int:comment_id>/delete', methods=['POST'])
@login_required
def delete_comment(comment_id):
comment = Comment.query.get_or_404(comment_id)
if comment.author != current_user and comment.article.author != current_user: # 只有评论者或文章作者可以删除
abort(403)
db.session.delete(comment)
db.session.commit()
flash('评论已删除!', 'success')
return redirect(url_for('article_detail', article_id=comment.article_id))
首页与分类页开发
实现首页展示文章列表,支持分页和分类筛选。
1. 首页开发
首页显示所有文章列表,支持分页。
使用Flask-Paginate实现分页:
pip install flask-paginate
定义分页逻辑:
from flask_paginate import Pagination, get_page_args
@app.route('/')
def home():
page, per_page, offset = get_page_args(page_parameter='page', per_page_parameter='per_page')
per_page = 5 # 每页显示5篇文章
offset = (page - 1) * per_page
articles = Article.query.order_by(Article.date_posted.desc()).offset(offset).limit(per_page).all()
total = Article.query.count()
pagination = Pagination(page=page, per_page=per_page, total=total, css_framework='bootstrap4')
return render_template('home.html', articles=articles, pagination=pagination)
在模板中使用pagination对象生成分页链接。
2. 分类页开发
添加分类模型:
class Category(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), unique=True, nullable=False)
articles = db.relationship('Article', secondary='article_category', backref=db.backref('categories', lazy=True))
# 创建关联表(多对多关系)
article_category = db.Table('article_category',
db.Column('article_id', db.Integer, db.ForeignKey('article.id'), primary_key=True),
db.Column('category_id', db.Integer, db.ForeignKey('category.id'), primary_key=True)
)
在Article模型中,通过backref引用categories。
创建筛选路由:
@app.route('/category/<int:category_id>')
def category_page(category_id):
category = Category.query.get_or_404(category_id)
page, per_page, offset = get_page_args()
per_page = 5
offset = (page - 1) * per_page
articles = Article.query.join(article_category).filter(article_category.c.category_id == category_id).order_by(Article.date_posted.desc()).offset(offset).limit(per_page).all()
total = Article.query.join(article_category).filter(article_category.c.category_id == category_id).count()
pagination = Pagination(page=page, per_page=per_page, total=total, css_framework='bootstrap4')
return render_template('category.html', category=category, articles=articles, pagination=pagination)
3. 分页与筛选
在上面的路由中,我们已经实现了分页。筛选可以通过查询参数进行,例如按分类筛选。在首页或分类页模板中,添加筛选表单(如按分类选择)。
处理筛选逻辑(示例在首页):
@app.route('/', methods=['GET', 'POST'])
def home():
category_id = request.args.get('category', type=int) # 从URL参数获取分类
page, per_page, offset = get_page_args()
per_page = 5
offset = (page - 1) * per_page
if category_id:
articles = Article.query.join(article_category).filter(article_category.c.category_id == category_id).order_by(Article.date_posted.desc()).offset(offset).limit(per_page).all()
total = Article.query.join(article_category).filter(article_category.c.category_id == category_id).count()
else:
articles = Article.query.order_by(Article.date_posted.desc()).offset(offset).limit(per_page).all()
total = Article.query.count()
pagination = Pagination(page=page, per_page=per_page, total=total, css_framework='bootstrap4')
categories = Category.query.all() # 获取所有分类用于筛选
return render_template('home.html', articles=articles, pagination=pagination, categories=categories, selected_category=category_id)
在模板中添加下拉菜单或链接以进行筛选。
总结
本教程详细介绍了Flask核心功能开发,包括用户模块、文章模块、评论模块以及首页与分类页的实现。通过代码示例和逐步解释,帮助新手快速上手。你可以根据需要扩展功能,如添加图片上传、搜索功能或更多权限控制。
下一步
- 学习Flask部署到生产环境。
- 探索更多Flask扩展,如Flask-RESTful用于API开发。
- 优化前端界面使用Bootstrap等框架。
如果你有更多问题,请参考Flask官方文档或社区资源。祝你学习愉快!