Flask 中文教程

第四部分:实战项目篇
第12章 入门级实战:个人博客系统
第13章 进阶级实战:RESTful API 服务
第五部分:部署运维与优化篇
第14章 Flask 应用部署
第15章 性能优化与安全加固
第六部分:问题解决与进阶篇
第16章 常见问题与解决方案
第17章 Flask 进阶与扩展

12.2 核心功能开发

Flask核心功能开发教程:用户模块、文章模块、评论模块与页面开发

Flask 中文教程

本教程详细讲解如何使用Flask框架实现核心功能,包括用户模块(注册、登录、个人信息管理)、文章模块(发布、编辑、删除、详情展示)、评论模块(提交、列表展示、权限控制)以及首页与分类页开发(分页、筛选)。内容适合新手,涵盖代码示例和步骤解释。

推荐工具
PyCharm专业版开发必备

功能强大的Python IDE,提供智能代码补全、代码分析、调试和测试工具,提高Python开发效率。特别适合处理列表等数据结构的开发工作。

了解更多

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官方文档或社区资源。祝你学习愉快!

开发工具推荐
Python开发者工具包

包含虚拟环境管理、代码格式化、依赖管理、测试框架等Python开发全流程工具,提高开发效率。特别适合处理复杂数据结构和算法。

获取工具包