Flask从入门到精通之大型程序的结构一
尽管在单一脚本中编写小型Web 程序很方便,但这种方法并不能广泛使用。程序变复杂后,使用单个大型源码文件会导致很多问题。不同于大多数其他的Web 框架,Flask 并不强制要求大型项目使用特定的组织方式,程序结构的组织方式完全由开发者决定。在本节,我们将介绍一种使用包和模块组织大型程序的方式。
一.项目结构
Flask 程序的基本结构如下所示:
|-blogs
|-app/
|-templates/
|-static/
|-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
这种结构有4 个顶级文件夹:
- Flask程序一般都保存在名为app 的包中
- 和之前一样,migrations文件夹包含数据库迁移脚本
- 单元测试编写在tests包中
- 和之前一样,venv 文件夹包含Python 虚拟环境
同时还创建了一些新文件:
- requirements.txt列出了所有依赖包,便于在其他电脑中重新生成相同的虚拟环境
- config.py 存储配置
- manage.py用于启动程序以及其他的程序任务
为了帮助你完全理解这个结构,下面几节讲解把前面介绍的hello.py 程序转换成这种结构的过程
二.配置选项
程序经常需要设定多个配置。这方面最好的例子就是开发、测试和生产环境要使用不同的数据库,这样才不会彼此影响。我们不再使用hello.py 中简单的字典状结构配置,而使用层次结构的配置类。config.py 文件的内容如下示例所示:
import os
basedir = os.path.abspath(os.path.dirname(__file__)) class Config:
SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string'
MAIL_SERVER = os.environ.get('MAIL_SERVER', 'smtp.googlemail.com')
MAIL_PORT = int(os.environ.get('MAIL_PORT', ''))
MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS', 'true').lower() in \
['true', 'on', '']
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
FLASKY_MAIL_SUBJECT_PREFIX = '[Flasky]'
FLASKY_MAIL_SENDER = 'Flasky Admin <flasky@example.com>'
FLASKY_ADMIN = os.environ.get('FLASKY_ADMIN')
SSL_REDIRECT = False
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_RECORD_QUERIES = True
FLASKY_POSTS_PER_PAGE =
FLASKY_FOLLOWERS_PER_PAGE =
FLASKY_COMMENTS_PER_PAGE =
FLASKY_SLOW_DB_QUERY_TIME = 0.5 @staticmethod
def init_app(app):
pass class DevelopmentConfig(Config):
DEBUG = True
SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite') class TestingConfig(Config):
TESTING = True
SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or \
'sqlite://'
WTF_CSRF_ENABLED = False class ProductionConfig(Config):
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, 'data.sqlite') @classmethod
def init_app(cls, app):
Config.init_app(app) # email errors to the administrators
import logging
from logging.handlers import SMTPHandler
credentials = None
secure = None
if getattr(cls, 'MAIL_USERNAME', None) is not None:
credentials = (cls.MAIL_USERNAME, cls.MAIL_PASSWORD)
if getattr(cls, 'MAIL_USE_TLS', None):
secure = ()
mail_handler = SMTPHandler(
mailhost=(cls.MAIL_SERVER, cls.MAIL_PORT),
fromaddr=cls.FLASKY_MAIL_SENDER,
toaddrs=[cls.FLASKY_ADMIN],
subject=cls.FLASKY_MAIL_SUBJECT_PREFIX + ' Application Error',
credentials=credentials,
secure=secure)
mail_handler.setLevel(logging.ERROR)
app.logger.addHandler(mail_handler) class HerokuConfig(ProductionConfig):
SSL_REDIRECT = True if os.environ.get('DYNO') else False @classmethod
def init_app(cls, app):
ProductionConfig.init_app(app) # handle reverse proxy server headers
from werkzeug.contrib.fixers import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app) # log to stderr
import logging
from logging import StreamHandler
file_handler = StreamHandler()
file_handler.setLevel(logging.INFO)
app.logger.addHandler(file_handler) class DockerConfig(ProductionConfig):
@classmethod
def init_app(cls, app):
ProductionConfig.init_app(app) # log to stderr
import logging
from logging import StreamHandler
file_handler = StreamHandler()
file_handler.setLevel(logging.INFO)
app.logger.addHandler(file_handler) class UnixConfig(ProductionConfig):
@classmethod
def init_app(cls, app):
ProductionConfig.init_app(app) # log to syslog
import logging
from logging.handlers import SysLogHandler
syslog_handler = SysLogHandler()
syslog_handler.setLevel(logging.INFO)
app.logger.addHandler(syslog_handler) config = {
'development': DevelopmentConfig,
'testing': TestingConfig,
'production': ProductionConfig,
'heroku': HerokuConfig,
'docker': DockerConfig,
'unix': UnixConfig, 'default': DevelopmentConfig
}
基类Config 中包含通用配置,子类分别定义专用的配置。如果需要,你还可添加其他配置类。为了让配置方式更灵活且更安全,某些配置可以从环境变量中导入。例如,SECRET_KEY 的值,这是个敏感信息,可以在环境中设定,但系统也提供了一个默认值,以防环境中没有定义。在3 个子类中,SQLALCHEMY_DATABASE_URI 变量都被指定了不同的值。这样程序就可在不同的配置环境中运行,每个环境都使用不同的数据库。配置类可以定义init_app() 类方法,其参数是程序实例。在这个方法中,可以执行对当前环境的配置初始化。现在,基类Config 中的init_app() 方法为空。在这个配置脚本末尾,config 字典中注册了不同的配置环境,而且还注册了一个默认配置。
三.启动脚本
顶级文件夹下的manage.py 文件用于启动程序。脚本内容如下:
#!/usr/bin/env python
import os
from app import create_app, db
from app.models import User, Role
from flask.ext.script import Manager, Shell
from flask.ext.migrate import Migrate, MigrateCommand
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
manager = Manager(app)
migrate = Migrate(app, db)
def make_shell_context():
return dict(app=app, db=db, User=User, Role=Role)
manager.add_command("shell", Shell(make_context=make_shell_context))
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
这个脚本先创建程序。如果已经定义了环境变量FLASK_CONFIG,则从中读取配置名;否则使用默认配置。然后初始化Flask-Script、Flask-Migrate 和为Python shell 定义的上下文。出于便利,脚本中加入了shebang 声明,所以在基于Unix 的操作系统中可以通过./manage.py 执行脚本,而不用使用复杂的python manage.py。
四.需求文件
程序中必须包含一个requirements.txt 文件,用于记录所有依赖包及其精确的版本号。如果要在另一台电脑上重新生成虚拟环境,这个文件的重要性就体现出来了,例如部署程序时使用的电脑。pip 可以使用如下命令自动生成这个文件:
pip freeze >requirements.txt
安装或升级包后,最好更新这个文件。需求文件的内容示例如下:
alembic==0.9.
bleach==2.0.
blinker==1.4
click==6.7
dominate==2.3.
Flask==0.12.
Flask-Bootstrap==3.3.7.1
Flask-HTTPAuth==3.2.
Flask-Login==0.4.
Flask-Mail==0.9.
Flask-Migrate==2.0.
Flask-Moment==0.5.
Flask-PageDown==0.2.
Flask-SQLAlchemy==2.2
Flask-WTF==0.14.
html5lib==0.999999999
itsdangerous==0.24
Jinja2==2.9.
Mako==1.0.
Markdown==2.6.
MarkupSafe==1.0
python-dateutil==2.6.
python-dotenv==0.6.
python-editor==1.0.
six==1.10.
SQLAlchemy==1.1.
visitor==0.1.
webencodings==0.5.
Werkzeug==0.12.
WTForms==2.1
如果你要创建这个虚拟环境的完全副本,可以创建一个新的虚拟环境,并在其上运行以下命令:
pip install -r requirements.txt
五.创建数据库
不管从哪里获取数据库URL,都要在新数据库中创建数据表。如果使用Flask-Migrate 跟踪迁移,可使用如下命令创建数据表或者升级到最新修订版本
python manage.py db upgrade
Flask从入门到精通之大型程序的结构一的更多相关文章
- Flask从入门到精通之大型程序的结构二
一.程序包 程序包用来保存程序的所有代码.模板和静态文件.我们可以把这个包直接称为app(应用),如果有需求,也可使用一个程序专用名字.templates 和static 文件夹是程序包的一部分,因此 ...
- Flask从入门到精通之flask程序入门
初始化 所有Flask程序都必须创建一个程序实例,Web服务器使用一种名为Web服务器网关接口的的协议(WSGI),把接收自客户端的所有请求转发给这个对象处理.程序实例是Flask类的对象,使用下面代 ...
- [ Python ] Flask 基于 Web开发 大型程序的结构实例解析
作为一个编程入门新手,Flask是我接触到的第一个Web框架.想要深入学习,就从<FlaskWeb开发:基于Python的Web应用开发实战>这本书入手,本书由于是翻译过来的中文版,理解起 ...
- Flask从入门到精通之Flask-Bootstrap的使用
Bootstrap(http://getbootstrap.com/)是Twitter 开发的一个开源框架,它提供的用户界面组件可用于创建整洁且具有吸引力的网页,而且这些网页还能兼容所有现代Web 浏 ...
- Flask从入门到精通之使用Flask-Migrate实现数据库迁移
在开发程序的过程中,你会发现有时需要修改数据库模型,而且修改之后还需要更新数据库.仅当数据库表不存在时,Flask-SQLAlchemy 才会根据模型进行创建.因此,更新表的唯一方式就是先删除旧表,不 ...
- Flask从入门到精通之使用Flask-SQLAlchemy管理数据库
Flask-SQLAlchemy 是一个Flask 扩展,简化了在Flask 程序中使用SQLAlchemy 的操作.SQLAlchemy 是一个很强大的关系型数据库框架,支持多种数据库后台.SQLA ...
- Flask从入门到精通之Flash消息
请求完成后,有时需要让用户知道状态发生了变化.这里可以使用确认消息.警告或者错误提醒.一个典型例子是,用户提交了有一项错误的登录表单后,服务器发回的响应重新渲染了登录表单,并在表单上面显示一个消息,提 ...
- Flask从入门到精通之重定向和用户会话
最新版的hello.py 存在一个可用性问题.用户输入名字后提交表单,然后点击浏览器的刷新按钮,会看到一个莫名其妙的警告,要求在再次提交表单之前进行确认.之所以出现这种情况,是因为刷新页面时浏览器会重 ...
- Flask从入门到精通之跨站请求伪造保护
默认情况下,Flask-WTF 能保护所有表单免受跨站请求伪造(Cross-Site Request Forgery,CSRF)的攻击.恶意网站把请求发送到被攻击者已登录的其他网站时就会引发CSRF ...
随机推荐
- Vue-cli 配置开发环境让测试服务器监听所有IP
//config/inex.js // Various Dev Server settingshost: '0.0.0.0', // can be overwritten by process.env ...
- 史上最全的Android开发学习教程集锦【初学者】
根据Google的报告,截止2017年5月为止,Android活跃用户已超过20亿,并还在持续增长中.Android系统在几个主要的市场上已超过了iOS系统,特别是在美国,欧洲和日本,然而苹果确实在中 ...
- 7.25 js 自定义方法 a.b
调用: $(function(){ Starinput.initiate({name:'qr1_z.startlevel',tar: $("#sitelogo1"), stars: ...
- 20155335俞昆《java程序设计》第七周总结
学号 2016-2017-2 <Java程序设计>第X周学习总结 ## 教材学习内容总结 Lambda 的语法概览 String[] names={“Justin”,”cater ...
- JavaScript 静态方法和实例方法
总结: 直接定义在构造函数上的方法和属性是静态的, 定义在构造函数的原型和实例上的方法和属性是非静态的 静态方法: function ClassA(){ //定义构造函数 }; ClassA.fun ...
- 2018.09.18 atcoder Best Representation(kmp)
传送门 思路简单不知为何调试了很久. 显然要么分成n个(所有字符相同),要么分成1个(原字符串无循环节),要么分成两个(有长度至少为2的循环节). 一开始以为可以直接hash搞定. 后来wa了几次之后 ...
- 2018.09.06 警卫安排(树形dp)
描述 太平王世子事件后,陆小凤成了皇上特聘的御前一品侍卫. 皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状:有边直接相连的宫殿可以互相望见.大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全 ...
- IntelliJ IDEA 2017版 开发SpringBoot的全局配置文件使用
一.全局配置文件 描述: Spring Boot项目使用一个全局的配置文件application.properties或者是application.yml,在resources目录下或者类路径 ...
- 疯狂安装oracle 12c,此版本没有scott这个用户
今天要学习oracle,然后寻思下个吧,结果出现了很多问题,在此分享一下,搞疯了,太痛苦了,学的教程是用的 Oracle 11g,我去官网下载的Oracle 12g,文件很大,好不容易装好了,寻思就这 ...
- 用Git将项目发布在GitHub里
转载自http://blog.csdn.net/u011572517/article/details/50537407,个人加了一些注意事项和解释. githud是一个程序员以后成长都会使用到的,先不 ...