基于Flask框架的任务清单管理系统

目录

一、项目简介

二、项目功能

三、技术分析

1、为什么选择Flask?

2、为什么选择 Mariadb ?

3、为什么选择Bootstrap?

四、Flask开发大型项目结构

1、项目结构

2、配置文件选项

3、程序工厂函数

1、为什么需要程序工厂函数?

2、如何实现程序工厂函数?

4、蓝图: 组件化开发

5、启动脚本

6、依赖包文件

7、单元测试

1、什么是单元测试?

2、如何实现单元测试?

3、unittest 核心概念及关系

4、任务清单单元测试的应用

5、项目需求文档

6、用户认证

7、技术要点

8、核心代码

9、测试代码

五、Flask-Login优化数据库模型

1、技术要点

2、核心代码

3、数据库创建

2、用户登录业务逻辑

3、测试方式

 六、用户邮箱验证

1、邮箱验证数据库模型

2、用户注册验证邮件的业务逻辑

3、电子邮件模板准备

4、电子邮件配置信息准备

5、发送电子邮件的业务逻辑

6、注册与确认验证的业务逻辑

七、基于Flask的任务清单管理系统(三): 用户资料

1、视图函数

2、前端页面

3、用户资料编辑

八、任务清单管理

1、数据库模型

2、表单文件

3、视图函数文件

4、分页展示


一、项目简介

任务清单管理系统采用 B S 架构,基于 Linux 平台开发。采用轻量级的 Web 服务器 Nginx , 其后端实现建议采用基于 Python 语言的 Flask 开源 Web 框架,进而增强扩展性。数据库采用关系型数据库 Mariadb ,前端的技术栈使用 Bootstrap 框架。该系统面向学生或者企业员工,提供任务添加、任务删除、任务完成标记, 任务搜索 ,可视化操作、数据实时展现等功能,目的在于轻松查看自己和他人的工作安排,合理规划手头任务。

二、项目功能

就像一般的 Todo List 应用一样, 实现了以下功能:
  • 管理数据库连接
  • 列出现有的待办事项
  • 创建新的待办事项
  • 检索单个待办事项
  • 编辑待办事项或标记待办事项
  • 删除待办事项

三、技术分析

1、为什么选择Flask?

  1. Flask是一个使用 Python 编写的轻量级 Web 应用框架。其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2 Flask使用 BSD 授权。
  2. Flask也被称为 “microframework” ,因为它使用简单的核心,用 extension 增加其他功能。
  3. Flask没有默认使用的数据库、窗体验证工具。
  4. 因此Flask是一个使用Python编写的轻量级Web应用框架。轻巧易扩展,而且够主流,有问题不怕找不到人问,最适合这种轻应用了。

2、为什么选择 Mariadb ?

  1. MariaDB 数据库管理系统是 MySQL一个分支,主要由开源社区在维护,采用 GPL 授权许可MariaDB 的目的是完全兼容 MySQL ,包括 API 和命令行,使之能轻松成为 MySQL 的代替品。
  2. MariaDB 虽然被视为 MySQL 数据库的替代品,但它在扩展功能、存储引擎以及一些新的功能改进方面都强过 MySQL 。而且从 MySQL 迁移到 MariaDB 也是非常简单的.

3、为什么选择Bootstrap?

  1. Bootstrap 是一个用于快速开发 Web 应用程序和网站的前端框架。Bootstrap 是基于 HTML、CSS、JavaScript 的。具有移动设备优先、浏览器支持良好、容易上手、响应式设计等。

四、Flask开发大型项目结构

1、项目结构

 
多文件 Flask 程序的基本结构 , 如下图所示 :
 
 
requirements.txt 列出了所有依赖包 , 便于在其他电脑中重新生成相同的虚拟环境 ;
config.py 存储配置 ;
manage.py 用于启动程序以及其他的程序任务。

2、配置文件选项

程序经常需要设定多个配置。一般分为开发、测试和生产环境 , 它们使用不同的数据库 , 不会彼此影响。
 
# config.py 
""" 
存储配置; 
""" 

import os 
# 获取当前项目的绝对路径; 
basedir = os.path.abspath(os.path.dirname(__file__))

class Config: 
""" 
所有配置环境的基类, 包含通用配置 
""" 

SECRET_KEY = os.environ.get('SECRET_KEY') or 'westos secret key' SQLALCHEMY_COMMIT_ON_TEARDOWN = True 
SQLALCHEMY_TRACK_MODIFICATIONS = True FLASKY_MAIL_SUBJECT_PREFIX = '[西部开源]' FLASKY_MAIL_SENDER = '976131979@qq.com' 

@staticmethod 
def init_app(app): 
pass 

class DevelopmentConfig(Config): 

""" 开发环境的配置信息 """ 

# 启用了调试支持,服务器会在代码修改后自动重新载入,并在发生错误时提供一个相当有用的调试 器。 

DEBUG = True 
MAIL_SERVER = 'smtp.qq.com' 
MAIL_PORT = 587 
MAIL_USE_TLS = True 
MAIL_USERNAME = os.environ.get('MAIL_USERNAME') or '976131979' 
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD') or '密码' 
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'data- dev.sqlite') class TestingConfig(Config): 

""" 测试环境的配置信息 """ 

TESTING = True 
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'data- test.sqlite') 

class ProductionConfig(Config): 

""" 生产环境的配置信息 """ 
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'data.sqlite') 

config = { 
'development': DevelopmentConfig, 
'testing': TestingConfig, 
'production': ProductionConfig, 
'default': DevelopmentConfig 
}

3、程序工厂函数

1、为什么需要程序工厂函数?

  1. 在单个文件中开发程序很方便,但却有个很大的缺点,因为程序在全局作用域中创建,所以无法动态修改配置。
  2. 运行脚本时,程序实例已经创建,再修改配置为时已晚。这一点对单元测试尤其重要,因为有时为了提高测试覆盖度,必须在不同的配置环境中运行程序。
  3. 这个问题的解决方法是延迟创建程序实例,把创建过程移到可显式调用的工厂函数中。
  4. 这种方法不仅可以给脚本留出配置程序的时间,还能够创建多个程序实例。

2、如何实现程序工厂函数?

创建扩展类时不向构造函数传入参数, 在之前创建的扩展对象上调用 init_app() 可以完成初始化过程。
不使用程序工厂函数 :
 
app = Flask(__name__) 
bootstrap = Bootstrap(app) 
mail = Mail(app)
使用程序工厂函数 :
 
bootstrap = Bootstrap() 
mail = Mail() 

def create_app(): 
    app = Flask(__name__) 
    bootstrap.init_app(app) 
    mail.init_app(app) 
    return app
app/__init__.py 文件详细代码如下 :
 
""" 
程序工厂函数, 延迟创建程序实例 
""" 

from flask import Flask 
from flask_bootstrap import Bootstrap 
from flask_mail import Mail 
from flask_sqlalchemy import SQLAlchemy 
from config import config 

bootstrap = Bootstrap() 
mail = Mail() 
db = SQLAlchemy() 

def create_app(config_name='development'): 

""" 默认创建开发环境的app对象 """ 

    app = Flask(__name__) 
    app.config.from_object(config[config_name]) 
    config[config_name].init_app(app) 
    bootstrap.init_app(app)

mail.init_app(app) 
db.init_app(app)
# 附加路由和自定义的错误页面 
# .........后续还需完善, 补充视图和错误页面 

return app

4、蓝图: 组件化开发

1)什么是蓝图 ?
  1. Flask蓝图提供了模块化管理程序路由的功能,使程序结构清晰、简单易懂。
  2. 假如说我们要为某所学校的每个人建立一份档案,一个很自然的优化方式就是这些档案如果能分类管理,就是说假如分为老师、学生、后勤人员等类别,那么后续查找和管理这些档案就方便清晰许多。
  3. Flask的蓝图就提供了类似分类的功能。
2)为什么使用蓝图 ?
  • 将不同的功能模块化
  • 构建大型应用
  • 优化项目结构
  • 增强可读性,易于维护
3)应用蓝图三部曲 ?
蓝图的创建 : app/auth/__init__.py
 
# 'auth'是蓝图的名称 
# __name__是蓝图所在路径 
auth =Blueprint('auth',__name__) 
from . import views
蓝图对象上注册路由 , 指定静态文件夹 , 注册模版过滤器 : app/auth/views.py
 
@auth.route('/') 
def auth_home(): 
    return 'auth_home'
注册蓝图对象 app/__init__.py
# url_prefix: 指定访问该蓝图中定义的视图函数时需要添加的前缀, 没有指定则不加; app.register_blueprint(auth,url_prefix='/auth')
访问网址 http://127.0.0.1:5000/auth/ 可以查看到 auth_home 的内容。
任务清单蓝图的应用
auth 蓝图
 
 
 
 
蓝图的创建 : app/auth/__init__.py
 
from flask import Blueprint 

# 实例化一个 Blueprint 类对象可以创建蓝本, 指定蓝本的名字和蓝本所在的包或模块 
auth = Blueprint('auth', __name__) 
# 把路由和错误处理程序与蓝本关联, 一定要写在最后, 防止循环导入依赖; 
from . import views, errors
蓝图对象上注册路由 , 指定静态文件夹 , 注册模版过滤器 : app/auth/views.py
 
from . import auth 

@auth.route('/login') 
def login(): 
    return 'login' 

@auth.route('/logout') 
def logout(): 
    return 'logout'
注册蓝图对象 app/__init__.py
 
def create_app(config_name='development'): 
""" 
默认创建开发环境的app对象 
""" 

# ...... # 附加路由和自定义的错误页面 
from app.auth import auth as auth_bp 
app.register_blueprint(auth_bp) # 注册蓝本 
from app.todo import todo as todo_bp 
app.register_blueprint(todo_bp, ) # 注册蓝本 


return app

5、启动脚本

顶级文件夹中的 manage.py 文件用于启动程序。
 
""" 
用于启动程序以及其他的程序任务。 
"""

from flask_migrate import Migrate, MigrateCommand 
from flask_script import Manager, Shell 

from app import create_app, db 

app = create_app('default') 
manager = Manager(app) 
migrate = Migrate(app, db) 

def make_shell_context(): 
    return dict(app=app, db=db) 

# 初始化 Flask-Script、Flask-Migrate 和为 Python shell 定义的上下文。 manager.add_command("shell", Shell(make_context=make_shell_context)) manager.add_command('db', MigrateCommand) 
if __name__ == '__main__': 
    manager.run()
基于 Unix 的操作系统中可以通过下面命令执行脚本 :
 
# python3 manage.py runserver --help 获取详细使用参数 

python3 manage.py runserver
效果如下 :
          
 
依次访问网址, 如果访问可以显示相关信息, 则成功。
  • http://127.0.0.1:5000/login
  • http://127.0.0.1:5000/logout
  • http://127.0.0.1:5000/todo/add/
  • http://127.0.0.1:5000/todo/delete/

6、依赖包文件

程序中必须包含一个 requirements.txt 文件,用于记录所有依赖包及其精确的版本号。

pip freeze > requirements.txt
创建一个和当前环境相同的虚拟环境 , 并在其上运行以下命令 :
 
pip install -r requirements.txt

7、单元测试

1、什么是单元测试?

单元测试也称之为 模块测试 ,是对程序设计中的最小单元 —— 函数进行测试的一种方法,所谓测试,就是验证我们自己编写的方法能不能够得到正确的结果,即用方法得到的结果与真实结果进行比对,这就称之为测试。

2、如何实现单元测试?

python 中有特别多的单元测试框架和工具, unittest , testtools , subunit , coverage ,testrepository , nose, mox , mock , fixtures , discover 等等,先不说如何写单元测试,光是怎么运行单元测试就有N 多种方法。 unittest ,作为标准 python 中的一个模块,是其它框架和工具的基
础。

3、unittest 核心概念及关系

TestCase 的实例就是一个测试用例。什么是测试用例呢?就是一个完整的测试流程,包括测试前准备环境的搭建( setUp ) ,执行测试代码 ( run ) ,以及测试后环境的还原 ( tearDown ) 。元测试( unit test ) 的本质也就在这里,一个测试用例是一个完整的测试单元,通过运行这个测试单元,可以对某一个问题进行验证。TestSuite 是多个测试用例的集合, TestSuite 也可以嵌套 TestSuite
TestLoader 是用来加载 TestCase TestSuite 中的,其中有几个 loadTestsFrom__() 方法,就是从各个地方寻找 TestCase ,创建它们的实例,然后 add TestSuite 中,再返回一个TestSuite 实例。TextTestRunner 是来执行测试用例的,其中的 run(test) 会执行 TestSuite/TestCase 中的run(result)方法。TextTestResult 保存测试的结果,包括运行了多少测试用例,成功了多少,失败了多少等信
息。
 
                    
 
测试范例
# tests/test_number.py i

mport random 
import unittest 

""" 
单独执行测试用例: python3 -m unittest test_number.py 
""" 

class TestSequenceFunctions(unittest.TestCase): 

"""
setUp() 和 tearDown() 方法分别在各测试前后运行,并且名字以 test_ 开头的函数都作为测试 执行。

""" 
def setUp(self): 
    self.seq = list(range(10)) 
def test_shuffle(self): 
# make sure the shuffled sequence does not lose any elements 
    random.shuffle(self.seq) 
    self.seq.sort() 
    self.assertEqual(self.seq, list(range(10))) 

# should raise an exception for an immutable sequence 
self.assertRaises(TypeError, random.shuffle, (1, 2, 3)) 

def test_choice(self): 
    element = random.choice(self.seq) 
    self.assertTrue(element in self.seq) 

def test_sample(self):
    with self.assertRaises(ValueError): 
        random.sample(self.seq, 20) 
    for element in random.sample(self.seq, 5):                     
        self.assertTrue(element in self.seq) 
def tearDown(self): 
    del self.seq
单独执行测试用例 :
 
python3 -m unittest test_number.py
运行结果如下 :
  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值