百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

干货满满!Python Flask 中级应用,构建任务管理系统全流程揭秘

zhezhongyun 2025-05-23 21:33 20 浏览

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 开发的道路上取得更多的成果!

#python自学##为什么要努力学习,为什么要读书##爆料##教程#

相关推荐

怎样设置EditText内部文字被锁定不可删除和修改

在做项目的时候,我曾经遇到过这样的要求,就是跟百度贴吧客户端上的一样,在回复帖子的时候,在EditText中显示回复人的名字,而且这个名字不可以修改和删除,说白了就是不可操作,只能在后面输入内容。在E...

iOS的布局体系-流式布局MyFlowLayout

iOS布局体系的概览在我的CSDN博客中的几篇文章分别介绍MyLayout布局体系中的视图从一个方向依次排列的线性布局(MyLinearLayout)、视图层叠且停靠于父布局视图某个位置的框架布局(M...

浏览器滚动条hover时变粗、改变颜色

今天应UED的要求对项目的滚动条进行美化,原生的滚动条虽然很实用,但确实不美观。用了一些css美化后::-webkit-scrollbar{height:9px;width:9...

QML控件类型:ComboBox、Control(qml buttongroup)

Control一、描述Control是所有控件通用功能的抽象基类型。它从窗口系统接收输入事件,并在屏幕上绘制自身。二、控件布局控件的implicitWidth和implicitHeight通...

学习CSS布局:简单表格布局代码示例

性能优化-学习CSS布局:简单表格布局代码示例CSS是现代Web设计和开发的必备技能之一。而表格布局是Web页面中常用的布局之一,用于展示数据和信息。在这篇文章中,我们将介绍如何使用CSS创建一个简单...

UE5之UMG基础第1篇:统一网格面板(ue5 新功能)

目标:记录和学习UE5的UMG方法制作UI,使用UniformGridPanel制作效果如下:步骤1.增加前言:UniformGridPanel统一网格面板,就是所有子元素大小和间隔等统一,这种效果...

JS的 DOM 尺寸与位置属性(js设置dom属性)

#头条深一度-深度阅读计划#在JavaScript开发中,操作DOM元素的尺寸和位置是常见的任务,尤其是在实现动画、布局调整或响应式设计时。本文将全面解析JavaScript中与DOM...

SpriteJS:图形库造轮子的那些事儿

从2017年到2020年,我花了大约4年的时间,从零到一,实现了一个可切换WebGL和Canvas2D渲染的,跨平台支持浏览器、SSR、小程序,基于DOM结构和支持响应式的,高...

理解CSS中的百分比单位:相对尺寸的核心规则

在CSS中,百分比(`%`)是一种灵活且强大的相对单位,但其具体行为常让开发者感到困惑。本文将深入解析百分比单位的计算规则,帮助你彻底掌握其背后的逻辑。一、百分比的核心:参考系(包含块)百分比的值始...

36个工作中常用的JavaScript函数片段「值得收藏」

作者:Eno_Yao转发链接:https://segmentfault.com/a/1190000022623676前言如果文章和笔记能带您一丝帮助或者启发,请不要吝啬你的赞和收藏,你的肯定是我前进的...

如何使用css完成视差滚动效果?(css 视距)

视差滚动(ParallaxScrolling)是指多层背景以不同的速度移动,形成立体的运动效果,带来非常出色的视觉体验我们可以把网页解刨成:背景层、内容层、悬浮层使用css形式实现视觉差滚动效果的方...

vant-List 列表(vant select)

引入importVuefrom'vue';import{List}from'vant';Vue.use(List);基础用法List组件通过lo...

Vue3问题:如何使用WangEditor富文本?能自定义才是真的会用!

笔者|大澈大家好,我是大澈!今天的问题,来自于上周末问题留言的朋友嘻嘻哈哈。欢迎大家在周末的问题留言推文中,积极进行问题留言,把这周工作日遇到的问题,分享给大家瞧瞧,或者直接进问答群,一起交流唠...

微信小程序开发极简入门(二):样式,页面,数据

前文:微信小程序开发极简入门(一)样式wxss:/**放在页面的wxss**/.scrollarea{flex:1;overflow-y:hidden;}.idx_view{...

AI+Code驱动的M站首页重构实践:从技术债务到智能化开发

本文分享了阿里巴巴找品M站首页重构项目中AI+Code提效的实践经验。面对M站技术栈陈旧、开发效率低下的挑战,我们通过楼层动态化架构重构和AI智能脚手架,实现了70%首页场景的标准化覆盖+30%的...