这部分内容在《Flask Web开发》里的相关章节讲的很详细,我就不重复了。在这里总结一下重点,再补充一些其他东西。
大型项目结构
小项目可以简单的只使用一个程序文件;大型项目需要更高效有序的结构,这是《Flask Web开发》里使用的结构:
|my_app
|-app/
|-templates/ 模板文件
|-static/ 静态文件(css、js等)
|-main/
|-__init__.py 创建蓝本
|-errors.py 错误处理
|-forms.py 表单类
|-views.py 路由
|-__init__.py 扩展和配置初始化、程序工厂函数、注册蓝本
|-email.py 邮件支持
|-models.py 数据库模型
|-migrations/ 数据库迁移脚本
|-tests/ 测试
|-__init__.py
|-test*.py
|-venv/ 虚拟环境
|-requirements.txt 需求文件
|-config.py 程序配置
|-manage.py 启动脚本
相对导入
《Flask Web开发》后半部分的代码片段省略掉了导入部分的内容,容易让人产生疑惑。因为这里使用包(Package)和模块(Module)来组织程序,所以使用了相对导入。
相对导入使用点来表示层级关系,一个点代表当前的包,两个点表示上一层包,以此类推(不建议超过两层)。引用PEP-328里的例子做说明:
|package/
|__init__.py
|subpackage1/
|__init__.py
|moduleX.py
|moduleY.py
|subpackage2/
|__init__.py
|moduleZ.py
|moduleA.py
在moduleX.py里,可以这样导入其他模块:
moduleX.py
from .moduleY import spam
from .moduleY import spam as ham
from . import moduleY
from ..subpackage1 import moduleY
from ..subpackage2.moduleZ import eggs
from ..moduleA import foo
from ...package import bar
当你导入某一个包内的模块,这个包里的__init__.py会被自动执行,所以如果要导入__init__.py中的内容,直接从该层包对应的点来导入:
moduleX.py
from . import spam # subpackage1下的__init__.py
from .. import spam # package下的__init__.py
为了更好的组织模块并增加命名层次空间,Python引入了包,包是一个有__init__.py(包的构造文件)文件的文件夹,可以理解成一种特殊的模块(__init__.py文件可以为空,也可以放一些初始化内容,它会在导入包内模块时自动执行, 类似Python类的构造函数 )。
|app/
|one/
|__init__.py
|hello2.py
|hello.py
这里的one文件夹就成了一个包,你可以在hello.py里导入one下面的hello2,使用点来表示层级关系:
from one.hello2 import spam
程序工厂函数和蓝本
简单来说,程序工厂函数就是一个用来创建程序实例的函数,即create_app(),在这个函数里完成扩展及配置的初始化操作,返回程序实例。使用程序工厂函数,我们可以延迟创建实例,在创建实例之前进行一些设置,还可以创建多个程序实例。
蓝本类似程序实例,但更多的是用来组织程序。
蓝本有很多重要作用。它可以更好的组织你的程序,比如把用户认证系统和主程序分开,使用不同的URL前缀,就像是划分文件夹,把Python程序的各个部分放在不同的包里一样。可以为不同的蓝本分配不同的模板文件夹和静态文件文件夹,设置不同的错误处理函数。和多个程序实例不同的是,它们(蓝本)可以共享相同的配置和扩展。
相关链接
- - - - -
更多关于Flask和Web开发的原创内容,欢迎关注 知乎专栏 - Hello, Flask! 。