任务清单管理系统采用 B/S 架构,基于 Linux 平台开发。采用轻量级的 Web 服务器 Nginx , 其后端实现建议采用基于 Python 语言的 Flask 开源 Web 框架,进而增强扩展性。
数据库采用关系型数据库 Mariadb ,前端的技术栈使用 Bootstrap 框架。该系统面向学生或者企业员工,提供任务添加、任务删除、任务完成标记, 任务搜索 ,可视化操作、数据实时展现等功能,目的在于轻松查看自己和他人的工作安排,合理规划手头任务。
就像一般的 Todo List 应用一样, 实现了以下功能:
Flask是一个使用 Python 编写的轻量级 Web 应用框架。其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2 。Flask使用 BSD 授权。
Flask也被称为 “microframework” ,因为它使用简单的核心,用 extension 增加其他功能。Flask没有默认使用的数据库、窗体验证工具。
因此Flask是一个使用Python编写的轻量级Web应用框架。轻巧易扩展,而且够主流,有问题不怕找不到人问,最适合这种轻应用了。
MariaDB 数据库管理系统是 MySQL的 一个分支,主要由开源社区在维护,采用 GPL 授权许可
MariaDB 的目的是完全兼容 MySQL ,包括 API 和命令行,使之能轻松成为 MySQL 的代替品。
MariaDB 虽然被视为 MySQL 数据库的替代品,但它在扩展功能、存储引擎以及一些新的功能改进方面都强过 MySQL 。而且从 MySQL 迁移到 MariaDB 也是非常简单的。
Bootstrap 是一个用于快速开发 Web 应用程序和网站的前端框架。Bootstrap 是基于 HTML、 CSS、JavaScript 的。具有移动设备优先、浏览器支持良好、容易上手、响应式设等。
程序经常需要设定多个配置。一般分为开发、测试和生产环境, 它们使用不同的数据库,不会彼此影响。
import os
#获取当前文件的目录名,即获取当前项目的绝对路径
basedir=os.path.abspath(os.path.dirname(__file__))
#print(basedir)
class Config:
"""
所有配置环境的基类,即不管是开发环境还是测试环境,配置相同的
都写在Config里面,包含通用配置,称为配置环境的基类
"""
SECRET_KEY=os.environ.get('SECRET_KEY') or 'westos secret key'
#尤其在涉及(flask-WTF)登陆页面提交敏感信息时,一定要设置密钥
SQLALCHEMY_COMMIT_ON_TEARDOM=True
#是否自动提交、
SQLALCHEMY_TRACK_MODIFICATIONS=True
#是否追踪修改,从Flask-SQLALchemy文档中查看
FLASK_MAIL_SUBJECT_PREFIX='安安的ToDolist'
FLASK_MAIL_SENDER='[email protected]'
@staticmethod
def init_app(app):
"""
初始化app,后续用来添加第三方插件
"""
pass
class DevelopmentConfig(Config):
"""
开发环境配置
"""
DEBUG=True
#启用调试支持,服务器会在代码修改后自动载入,并在发生错误时提供一个相当有用的调试器
MAIL_SERVER='smtp.qq.com'
MAIL_PORT=587
MAIL_USE_TLS=True
#这里的os.environ.get()指从系统的环境中获取(),environ是与Linux配套的
MAIL_USERNAME=os.environ.get('MAIL_USERNAME') or '792910452'
MAIL_PASSWORD=os.environ.get('MAIL_PASSWORD') or '密码'
SQLALCHEMY_DATABASE_URI='sqlite:///' + os.path.join(basedir,'data-dev.sqlite')
#开发环境下的数据存放在当前文件下的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
#默认是在开发环境中
}
在单个文件中开发程序很方便,但却有个很大的缺点,因为程序在全局作用域中创建,所以无法动态修改配置。运行脚本时,程序实例已经创建,再修改配置为时已晚。这一点对单元测试尤其重要,因为有时为了提高测试覆盖度,必须在不同的配置环境中运行程序。
这个问题的解决方法是延迟创建程序实例,把创建过程移到可显式调用的工厂函数中。这种方法不仅可以给脚本留出配置程序的时间,还能够创建多个程序实例。
创建扩展类时不向构造函数传入参数,在之前创建的扩展对象上调用 init_app() 可以完成初始化过程。
#不使用程序工厂函数创建实例:
app = Flask(__name__)
bootstrap = Bootstrap(app)
mail = Mail(app)
"""
使用程序工厂函数,延迟创建程序实例
延迟创建flask应用
应用场景如下:
1)测试:可以使用多个应用程序的实例。为每一种实例分配不同的配置,从而测试每一种不同的情况
2)多个实例,要同时运行同一应用的不同版本。可以在你的Web服务器中创建多个实例并分配不同的配置
"""
#程序工厂函数创建实例:
#首先实例化函数,再在需要的时候与实例结合从而创建实例,便于后续#代码修改维护
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()
db=SQLAlchemy()
mail=Mail()
def create_app(config_name='development'):
"""
默认创建开发环境的app实例
"""
app=Flask(__name__)
app.config.from_object(config[config_name])
#导入配置信息
config[config_name].init_app(app)
#初始化app
bootstrap.init_app(app)
db.init_app(app)
mail.init_app(app)
return app
Flask蓝图提供了模块化管理程序路由的功能,使程序结构清晰、简单易懂。
假如说我们要为某所学校的每个人建立一份档案,一个很自然的优化方式就是这些档案如果能分类管理,就是说假如分为老师、学生、后勤人员等类别,那么后续查找和管理这些档案就方便清晰许多。Flask的蓝图就提供了类似“分类”的功能。
1)创建蓝图
"""
from flask import Blueprint
#实例化一个蓝图对象,指定蓝图的名字和蓝图所在的位置
auth=Blueprint('auth',__name__)
#将路由与蓝本关联,一定要写在最后,防止循环导入
from . import views
蓝图对象注册路由,指定静态文件夹,注册模板过滤器:app/auth/views.py
2)应用蓝图
"""
from app.auth import auth
@auth.route('/')
def index():
return 'index'
@auth.route('/register')
def register():
return 'register'
@auth.route('/login')
def login():
return 'login'
@auth.route('/logout')
def logout():
return 'logout'
#3)注册蓝图,将蓝图实例与app关联起来
from app.auth import auth
app.register_blueprint(auth,url_prefix='/auth')
todo蓝图,同auth蓝图一样
1)创建蓝图
"""
from flask import Blueprint
todo=Blueprint('todo',__name__)
from . import views
#将路由与蓝图关联起来
蓝图对象上注册路由,指定静态文件夹,注册模版过滤器
2)应用蓝图
"""
from app.todo import todo
@todo.route('add')
def add():
return 'todo add'
@todo.route('delete')
def delete():
return 'todo delete'
from app.todo import todo
app.register_blueprint(todo,url_prefix='/todo')
顶级文件夹中的manage.py文件用于启动程序。
from app import create_app
def make_shell_context():
return dict(app=app,name='anan',age=10)
if __name__ == '__main__':
#app=create_app()
#host='0.0.0.0'其中0表示任意,这个IP则表示我的IP地址在共享时可以和任意一个IP地址绑定在一起
#app.run()
from flask_script import Manager,Shell
app=create_app()
manager=Manager(app)
#初始化 Flask-Script、Flask-Migrate和为Python shell定义的上下文
manager.add_command('shell',Shell(make_context=make_shell_context))
manager.run()
在terminal中通过下面命令执行脚本:
python manage.py runserver
程序中必须包含一个requirement.txt文件,用于记录所有依赖包及其精确的版本号。
pip freeze >requirement.txt
创建一个和当前环境相同的虚拟环境,并在其上运行以下命令(迭代的安装项目需要的第三方模块):
pip install -r requirement.txt
单元测试也称之为“模块测试”,是对程序设计中的最小单元——函数进行测试的一种方法,所谓测试,就是验证我们自己编写的方法能不能得到正确的结果,即将用方法得到的结果与真实结果进行比对,这就称之为测试。
python中有特别多的单元测试框架和工具,unittest,testtools,subunit,coverage,testrepository,nose,mox,mock,fixtures,discover等等,先不说如何写单元测试,光是怎么运行单元测试就有N多种方法。 unittest,作为标准python中的一个模块,是其它框架和工具的基础。
#test/test_number.py
import unittest
from random import random
class TestSequenceFunctions(unittest.TestCase):
"""
setup()和tearDown()方法分别在各测试前后运行,并且名字以test_开头
的函数都作为测试执行
"""
def setUp(self) -> None:
self.seq=[0,1,2,3,4,5,6,7]
def test_choice_ok(self):
item=random.choice(self.seq)
result=item in self.seq
self.assertTrue(result)
def test_sample_ok(self):
result=random.sample(self.seq,4)
self.assertEqual(len(result),4)
def tearDown(self) -> None:
del self.seq
单独执行测试用例:
python -m unittest test_number.py
第一个测试确保程序实例存在。第二个测试确保程序在测试配置中运行。
若想把 tests 文件夹作为包使用,需要添加 tests/init.py 文件,不过这个文件可以为空,因为 unittest 包会扫描所有模块并查找测试。
#test/test_basics.py
import unittest
from flask import current_app
from app import create_app,db
class BasicsTestCase(unittest.TestCase):
"""
setup()和tearDown()方法分别在各测试前后运行,并且名字以test_
开头的函数都作为测试执行
"""
def setup(self):
"""
在测试前创建一个测试环境:
1)使用测试配置创建程序
2)激活上下文,确保能在测试中使用current_app
3)创建一个全新的数据库,以备不时之需
"""
self.app=create_app('testing')
self.app_context=self.app.app_context()
#将app_context与当前环境结合
self.app_context.push()
db.create_all()
def tearDown(self) -> None:
db.session.remove()
db.drop_all()
def test_app_exists(self):
"""
测试当前app是否存在
"""
self.assertFalse(current_app is None)
def test_app_is_testing(self):
"""
测试当前app是否为测试环境
"""
self.assertTrue(current_app.config['TESTING'])
为了运行单元测试,在manage.py脚本中添加一个自定义命令。
#manage.py
@manager.command
def tests():
"""
执行Flask项目的测试用例
"""
import unittest
#将发现的所有app测试用例(testcase)绑定为测试集合(testsuite),使用testloader进行绑定
tests=unittest.TestLoader().discover('tests')
#verbosity是测试结果的复杂度,有0,1,2三种复杂度
unittest.TextTestRunner(verbosity=2).run(tests)
单元测试使用下面命令运行:
python manage.py tests
文件 README.md , 建议包含项目介绍, 项目功能, 项目技术栈和项目最终演示效果。
Git(读音为/gɪt/)是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。
Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。
试想一下,在没有版本管理工具出现之前,我们该如何实现代码的整合和备份管理?
GitHub是一个面向开源及私有软件项目的托管平台,因为只支持git 作为唯一的版本库格式进行托管,故名GitHub。
Github从诞生之初,就有着另外两个非凡的使命:
这两部分业务是最核心粘性最大的,也是Github的核心竞争力。
截至2017年4月,GitHub报告有近2000万用户和5700万个项目,其中不乏知名开源项目Ruby on Rails、jQuery、python等。
初始化项目为Git仓库,将项目文件添加到暂存区,提交到本地仓库,最终上传到远程仓库Github
# 初始化项目为Git仓库
git init Initialized empty Git repository in /home/kiosk/Desktop/201905python/Todolist/.git/ # 将所有项目文件添加到暂存区
git add *
# 提交到本地仓库
git commit -m "Flask任务清单管理系统(一): 大型项目结构化管理"
# 添加一个新的远程仓库, 第一次需要, 后面的不需要添加.
git remote add origin https://github.com/lvah/TodoList.git
# 上传项目至远程仓库`Github
git push -u origin master