干货满满!Python Flask 中级应用,构建任务管理系统全流程揭秘
zhezhongyun 2025-05-23 21:33 3 浏览
Python Flask开发Web服务:中级实战教程
Flask是一个轻量级的Python Web框架,以其灵活性和扩展性而受到开发者的喜爱。本教程将带你从基础到实战,通过一个完整的案例来深入学习Flask的中级应用开发。
一、Flask核心特性回顾
在进入中级内容之前,让我们快速回顾一下Flask的核心特性:
1. 轻量级:Flask本身非常轻量,但可以通过扩展来构建复杂的应用。这意味着它不会给你的项目带来过多的负担,你可以根据实际需求灵活地添加功能。
2. 灵活性:开发者可以根据项目需求选择所需的组件。不像一些大型框架有固定的结构和模式,Flask允许你自由地组合各种库和工具来实现你的目标。
3. 模板引擎:内建支持Jinja2模板,方便HTML页面的渲染。Jinja2提供了强大的模板语法,如变量替换、条件语句、循环语句等,使你能够轻松地将数据动态地展示在页面上。
4. 扩展性:通过丰富的扩展(如Flask-SQLAlchemy、Flask-WTF等),可以轻松实现数据库操作、表单处理等功能。这些扩展经过了大量的测试和优化,能够帮助你快速地开发出功能强大的应用。
二、中级实战案例:构建一个任务管理应用
(一)项目需求
我们将构建一个简单的任务管理应用,用户可以添加任务、查看任务列表、更新任务状态和删除任务。这个应用可以帮助用户更好地组织和管理自己的任务,提高工作效率。
(二)项目结构
为了保持代码的清晰和可维护性,我们将项目结构设计如下:
task_manager/
│
├── app/
│ ├── __init__.py # 应用初始化文件,创建Flask应用实例并配置相关扩展
│ ├── routes.py # 定义应用的路由和视图函数
│ ├── templates/
│ │ ├── base.html # 所有页面的基模板,包含页面的基本结构和公共部分
│ │ ├── index.html # 任务列表页面的模板
│ │ └── task.html # 任务详情和编辑页面的模板
│ ├── models.py # 定义数据库模型,与数据库表进行映射
│ └── forms.py # 定义表单类,用于处理用户输入和验证
│
├── config.py # 应用的配置文件,包含密钥、数据库连接等配置
└── run.py # 应用的入口文件,启动Flask应用
(三)安装依赖
在项目根目录下创建一个requirements.txt文件,列出所有依赖:
Flask==2.2.2
Flask-SQLAlchemy==3.0.3
Flask-Migrate==4.0.4
Flask-WTF==1.1.1
然后运行以下命令安装依赖:
pip install -r requirements.txt
可能遇到的问题及解决方案:
1. 依赖冲突:如果你的Python环境中已经安装了其他版本的相关库,可能会导致依赖冲突。解决方法是升级或降级相关库到兼容的版本,或者创建一个新的虚拟环境来安装依赖。
2. 网络问题:如果在安装过程中遇到网络连接问题,可以尝试更换pip源,例如使用国内的镜像源(如清华大学开源软件镜像站)。
(四)配置文件
在config.py中定义应用的配置:
import os
class Config:
# 应用的密钥,用于加密会话等安全相关的操作
# 可以从环境变量中获取,如果没有则使用默认值
SECRET_KEY = os.environ.get('SECRET_KEY') or 'you-will-never-guess'
# 数据库连接字符串,从环境变量中获取,如果没有则使用SQLite数据库
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or'sqlite:///site.db'
# 关闭SQLAlchemy的修改跟踪功能,以提高性能
SQLALCHEMY_TRACK_MODIFICATIONS = False
说明:
1. SECRET_KEY是一个重要的配置项,用于保证应用的安全性。在生产环境中,应该将其设置为一个强密码,并通过环境变量来传递,而不是使用默认值。
2. SQLALCHEMY_DATABASE_URI指定了应用连接的数据库。这里使用了SQLite作为默认数据库,适合开发和测试阶段。在生产环境中,可以根据实际情况更换为其他数据库,如MySQL或PostgreSQL。
(五)初始化应用
在app/init.py中初始化Flask应用:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
# 创建Flask应用实例
app = Flask(__name__)
# 从config模块中加载配置
app.config.from_object('config.Config')
# 创建SQLAlchemy数据库对象
db = SQLAlchemy(app)
# 创建数据库迁移对象
migrate = Migrate(app, db)
# 导入路由和模型模块,避免循环导入问题
from app import routes, models
说明:
1. Flask(__name__)创建了一个Flask应用实例,__name__是Python的一个特殊变量,它的值取决于模块的导入方式,Flask使用它来确定应用的根目录。
2. app.config.from_object('config.Config')将配置类Config中的配置项加载到应用中。
3. SQLAlchemy(app)创建了一个与Flask应用关联的SQLAlchemy对象,用于操作数据库。
4. Migrate(app, db)创建了一个数据库迁移对象,用于管理数据库的版本控制。
5. 最后导入routes和models模块,这样可以在应用初始化完成后,让Flask能够识别和处理定义的路由和模型。
(六)数据库模型
在models.py中定义数据库模型:
from datetime import datetime
from app import db
# 定义Task数据库模型类,继承自db.Model
class Task(db.Model):
# 任务的唯一标识,整数类型,为主键
id = db.Column(db.Integer, primary_key=True)
# 任务的标题,字符串类型,不能为空
title = db.Column(db.String(100), nullable=False)
# 任务的描述,文本类型,可以为空
description = db.Column(db.Text, nullable=True)
# 任务的完成状态,布尔类型,默认为False
completed = db.Column(db.Boolean, default=False)
# 任务的创建时间,日期时间类型,默认为当前的UTC时间
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
# 定义对象的字符串表示形式,方便调试和日志记录
def __repr__(self):
return f"Task('{self.title}', '{self.created_at}')"
运行以下命令创建数据库迁移脚本并应用迁移:
flask db init
flask db migrate -m "Initial migration."
flask db upgrade
说明:
1. db.Column用于定义数据库表的列,每个列都有一个类型(如db.Integer、db.String等)和一些可选的参数(如nullable、default等)。
2. __repr__方法返回对象的字符串表示形式,在调试和打印对象时非常有用。
3. 数据库迁移命令:
o flask db init初始化数据库迁移环境,创建一个migrations文件夹,用于存储迁移脚本。
o flask db migrate -m "Initial migration."根据模型类的定义生成一个迁移脚本,并添加一个描述信息。
o flask db upgrade应用迁移脚本,将数据库结构更新为与模型类定义一致。
(七)表单
在forms.py中定义表单:
from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField, BooleanField, SubmitField
from wtforms.validators import DataRequired
# 定义TaskForm表单类,继承自FlaskForm
class TaskForm(FlaskForm):
# 任务标题字段,字符串类型,必填项
title = StringField('Title', validators=[DataRequired()])
# 任务描述字段,文本区域类型
description = TextAreaField('Description')
# 任务完成状态字段,布尔类型
completed = BooleanField('Completed')
# 提交按钮字段
submit = SubmitField('Submit')
说明:
1. FlaskForm是Flask-WTF扩展提供的基类,用于创建表单类。
2. StringField、TextAreaField、BooleanField和SubmitField分别表示不同类型的表单字段。
3. DataRequired验证器用于确保字段不为空,当用户提交表单时,如果该字段为空,将会显示错误信息。
(八)路由与视图
在routes.py中定义路由和视图函数:
from flask import render_template, redirect, url_for, flash
from app import app, db
from app.forms import TaskForm
from app.models import Task
# 定义根路由和/index路由,显示任务列表页面
@app.route('/')
@app.route('/index')
def index():
# 查询所有任务
tasks = Task.query.all()
# 渲染index.html模板,并传递任务列表数据
return render_template('index.html', tasks=tasks)
# 定义/new_task路由,处理添加新任务的请求
@app.route('/task/new', methods=['GET', 'POST'])
def new_task():
# 创建TaskForm表单实例
form = TaskForm()
# 如果表单数据通过验证
if form.validate_on_submit():
# 创建一个新的Task对象
task = Task(title=form.title.data, description=form.description.data, completed=form.completed.data)
# 将新任务添加到数据库会话中
db.session.add(task)
# 提交数据库会话,将新任务保存到数据库中
db.session.commit()
# 显示成功消息
flash('Your task has been created!','success')
# 重定向到任务列表页面
return redirect(url_for('index'))
# 渲染task.html模板,并传递表单对象和标题
return render_template('task.html', form=form, legend='New Task')
# 定义/task/<int:task_id>路由,处理更新任务的请求
@app.route('/task/<int:task_id>', methods=['GET', 'POST'])
def update_task(task_id):
# 根据任务ID查询任务对象,如果不存在则返回404错误
task = Task.query.get_or_404(task_id)
# 创建TaskForm表单实例,并使用任务对象的数据填充表单
form = TaskForm(obj=task)
# 如果表单数据通过验证
if form.validate_on_submit():
# 更新任务对象的属性
task.title = form.title.data
task.description = form.description.data
task.completed = form.completed.data
# 提交数据库会话,将更新后的任务保存到数据库中
db.session.commit()
# 显示成功消息
flash('Your task has been updated!','success')
# 重定向到任务列表页面
return redirect(url_for('index'))
# 渲染task.html模板,并传递表单对象和标题
return render_template('task.html', form=form, legend='Update Task')
# 定义/task/delete/<int:task_id>路由,处理删除任务的请求
@app.route('/task/delete/<int:task_id>')
def delete_task(task_id):
# 根据任务ID查询任务对象,如果不存在则返回404错误
task = Task.query.get_or_404(task_id)
# 从数据库会话中删除任务对象
db.session.delete(task)
# 提交数据库会话,将删除操作保存到数据库中
db.session.commit()
# 显示成功消息
flash('Your task has been deleted!','success')
# 重定向到任务列表页面
return redirect(url_for('index'))
说明:
1. render_template用于渲染指定的模板文件,并传递数据到模板中。
2. redirect用于重定向到指定的URL。
3. url_for根据视图函数的名称生成对应的URL。
4. flash用于在页面上显示消息,消息的类别(如'success')可以用于在模板中设置不同的样式。
5. 在处理表单提交时,form.validate_on_submit()方法会验证表单数据是否符合验证器的要求。如果验证通过,则执行相应的操作(如添加、更新或删除任务)。
(九)模板
在templates文件夹中创建HTML模板文件。
base.html
这是所有页面的基模板:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }}</title>
<!-- 引入Bootstrap CSS样式表,用于美化页面 -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
<!-- 导航栏 -->
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="{{ url_for('index') }}">Task Manager</a>
<div class="collapse navbar-collapse">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="{{ url_for('index') }}">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('new_task') }}">New Task</a>
</li>
</ul>
</div>
</nav>
<div class="container">
<!-- 显示Flash消息 -->
{% 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>
</body>
</html>
说明:
1. {{ title }}是一个Jinja2模板变量,用于显示页面的标题,具体的值在视图函数中传递。
2. url_for('index')和url_for('new_task')用于生成对应的URL,这样可以确保链接的正确性,并且在应用的URL发生变化时,不需要手动修改所有的链接。
3. get_flashed_messages(with_categories=true)用于获取Flash消息及其类别,并通过循环遍历显示在页面上。
4. {% block content %}{% endblock %}是一个模板块,具体页面的内容将填充在这个块中。
index.html
任务列表页面:
{% extends "base.html" %}
{% block content %}
<h1>Task List</h1>
<ul>
{% for task in tasks %}
<li>
<a href="{{ url_for('update_task', task_id=task.id) }}">{{ task.title }}</a>
<span>{{ task.description }}</span>
<span>{{ 'Completed' if task.completed else 'Not Completed' }}</span>
<a href="{{ url_for('delete_task', task_id=task.id) }}">Delete</a>
</li>
{% endfor %}
</ul>
<a href="{{ url_for('new_task') }}">Add New Task</a>
{% endblock %}
说明:
1. {% extends "base.html" %}表示该模板继承自base.html模板,将使用base.html的基本结构和样式。
2. {% for task in tasks %}循环遍历任务列表,并显示每个任务的标题、描述、完成状态和删除链接。
3. {{ 'Completed' if task.completed else 'Not Completed' }}是一个Jinja2条件表达式,根据任务的完成状态显示相应的文本。
task.html
任务详情和编辑页面:
{% extends "base.html" %}
{% block content %}
<h1>{{ legend }}</h1>
<form method="POST">
{{ form.hidden_tag() }}
<div class="form-group">
{{ form.title.label }}<br>
{{ form.title(size=32) }}<br>
</div>
<div class="form-group">
{{ form.description.label }}<br>
{{ form.description(rows=4) }}<br>
</div>
<div class="form-group">
{{ form.completed.label }}<br>
{{ form.completed }}<br>
</div>
<div class="form-group">
{{ form.submit() }}<br>
</div>
</form>
{% endblock %}
说明:
1. {{ legend }}用于显示页面的标题,具体的值在视图函数中传递。
2. {{ form.hidden_tag() }}生成一个隐藏的表单字段,用于保护CSRF(跨站请求伪造)。
3. {{ form.title.label }}、`{{ form.description.label }} 等用于显示表单字段的标签,{{ form.title(size=32) }} 等用于显示表单字段的输入框,size 和 rows 等参数用于设置输入框的样式和大小。
(十)运行应用
在run.py中运行应用:
from app import app
if __name__ == '__main__':
app.run(debug=True)
说明:
if __name__ == '__main__': 语句确保只有当直接运行 run.py 文件时,才会启动 Flask 应用。app.run(debug=True) 以调试模式启动应用,在调试模式下,应用会在代码发生变化时自动重新加载,并且会显示详细的错误信息,方便开发和调试。但在生产环境中,应将 debug 设置为 False,并使用更合适的 Web 服务器(如 Gunicorn 或 uWSGI)来部署应用。
可能遇到的问题及解决方案:
1. 端口冲突:如果当前端口已被占用,Flask 会提示端口已被使用的错误。解决方法是修改 app.run() 中的 port 参数,指定一个未被占用的端口,例如 app.run(debug=True, port=5001)。
2. 数据库连接问题:如果数据库配置不正确,可能会导致连接数据库失败。请检查 config.py 中的数据库连接字符串是否正确,并确保数据库服务已经启动。
通过以上步骤,你已经成功构建了一个简单的任务管理应用。你可以根据自己的需求进一步扩展和优化这个应用,例如添加用户认证、权限管理、任务分类等功能。
希望本教程能帮助你更好地掌握 Flask 的中级应用开发,祝你在 Web 开发的道路上取得更多的成果!
相关推荐
- 平和!晨间攻克 HTML 表格属性题,面试难题轻松化解
-
当清晨的阳光轻轻洒在窗台,泡上一杯淡雅的茉莉茶,翻开这篇文章,就像开启一场宁静的知识对话。前端面试中那些让人有些头疼的HTML表格属性问题,今天咱们不慌不忙,慢慢梳理,把它们变成面试时的底气,让焦...
- 高效设计表格 - 用我们的HTML表格生成器轻松搞定
-
在图形开发领域,效率和质量是我们所追求的。HTML表格生成器(HTML表格生成器-在线工具|图形开发学院),以其简洁的界面、高效的性能和人性化的设计,降低了图形开发的门槛,让每一位用户都能...
- 一看就懂的Excel表格的基本操作的十大技巧
-
Excel表格已经成为Office人员最常用的数据处理软件,Excel表格的基本操作视频教程也成为Excel表格初学者急着寻找的资料之一。其实,普通人需要用到的Excel的功能不到其全部功能的10%。...
- 干货满满!Python Flask 中级应用,构建任务管理系统全流程揭秘
-
PythonFlask开发Web服务:中级实战教程Flask是一个轻量级的PythonWeb框架,以其灵活性和扩展性而受到开发者的喜爱。本教程将带你从基础到实战,通过一个完整的案例来深入学习Fla...
- php手把手教你做网站(二十)vue+tp6简单案例(demo)
-
很多时候搭建好了环境,但是不知道怎么入手去开发。下面我们通过简单案例说明如何快速入门开发模块:例1:开发helloworld模块搭建好环境,新建项目以后,进入项目所在文件夹,依次进入src/compo...
- 前端经验-如何在p元素中展示固定行数的文字,超出部分显示省略号
-
1说明最近项目上有个需求,就是有一个网站列表,每个网站下面要加上一段简介,简介文字有行数限制,超出行数以后后面的文字用省略号显示。2CSS代码.websiteulp{margin:...
- jQuery 动画制作与特效
-
使用show()和hide()方法在普通的javascript编程中,要实现元素的显示、隐藏通常是利用其CSS的display属性或者visibility属性。在jQuery中提供了show()和hi...
- 抓狂!代码混乱漏洞百出?7 个技巧助你逆袭成大神
-
写JavaScript代码时,是不是经常遇到这种崩溃瞬间:数组越界报错、异步请求乱成麻、页面交互卡到怀疑人生?别让这些“老大难”问题拖慢你的开发进度!今天手把手教你7个超实用的JavaS...
- 玩转Markdown(2)——抽象语法树的提取与操纵
-
上一篇玩转Markdown——数据的分离存储与组件的原生渲染发布,转眼已经鸽了大半年了。最近在操纵mdast生成md文件的时候,心血来潮,把玩转Markdown(2)给补上了。这一...
- 关于ul里边的li浮动后边的p不独占一行问题
-
为什么ul里面的li元素浮动起来以后本应该独占一行的P标签会跟着上去贴着li元素的内容呢?引入的一个CSS里面把除非设置Ul的行高,这样P标签才会下拉,这是为什么?下图是出来的没加css效果刚开始我...
- 用css设计电子相册 下
-
本篇学习资料讲解:延续上一篇的学习资料,仍然介绍使用css对电子相册进行排版和侧面强调“盒子模型、标准流、浮动和定位”的重要性。上篇学习资料介绍的“阵列模式电子相册”,如果也能够看到详细信息就更...
- 第六次记录,利用CSS调整样式位置
-
本小节基本要求:了解标签的父子关系要点:1、如何对父标签下的子标签进行样式修改2、display-inline-block;3、绝对定位absolute4、margin与padding5、以上是关键,...
- 在WordPress中如何按照类别显示最近的文章
-
最近许多用户在寻找一种在网站的侧边栏按照文章的类别来显示文章的方法。文章显示如下图:这里给大家介绍两种方法,通过这两种方法均可以实现在WordPress网站侧边栏按类别显示文章。第一种方法比较适合初学...
- 初识CSS——布局小技巧
-
#大有学问##头条创作挑战赛#垂直对齐作用用于设置图片或者表单等行内块元素和文字的垂直对齐。垂直对齐只针对行内元素或者行内块元素有效。语法vertical-align:baseline|top...
- 一篇文章教会你如何制做精美导航条
-
【一、项目背景】让更多的人去学习html,以广东科技学院的导航栏为例,教大家怎么去做一个横向的导航栏。【二、项目准备】准备一个编程的软件Dreamweaver,打开软件点击文件新建一个叫导航栏的...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 教程 (33)
- HTML 简介 (35)
- HTML 实例/测验 (32)
- HTML 测验 (32)
- HTML 参考手册 (28)
- JavaScript 和 HTML DOM 参考手册 (32)
- HTML 拓展阅读 (30)
- HTML常用标签 (29)
- HTML文本框样式 (31)
- HTML滚动条样式 (34)
- HTML5 浏览器支持 (33)
- HTML5 新元素 (33)
- HTML5 WebSocket (30)
- HTML5 代码规范 (32)
- HTML5 标签 (717)
- HTML5 标签 (已废弃) (75)
- HTML5电子书 (32)
- HTML5开发工具 (34)
- HTML5小游戏源码 (34)
- HTML5模板下载 (30)
- HTTP 状态消息 (33)
- HTTP 方法:GET 对比 POST (33)
- 键盘快捷键 (35)
- 标签 (226)
- HTML button formtarget 属性 (30)