在钱咖使用Flask中,我们对Flask做了一定扩展,主要集中在以下几方面

  • 服务端会话( session )存放在 Redis 中
  • 支持 webassets 来实现犹如 Rails pipeline 似的 assets 管道输出静态/动态资源文件
  • 对 Flask-SQLAlchemy 进行改造,更便利地使用多个数据源
  • 根据需要从数据反射出数据模型类,无需提前写模型数据类源代码

:我们使用的Python版本是3.4。

示例项目源代码

这里获取源代码,并根据 README.md 里的指示安装基本环境。

Python package

为了在源代码中引用其他模块的方便,我们约定每个基于Flask的项目需要定义成一个Python包,在项目的根目录写这样一个 setup.py

### setup.py

from setuptools import setup


setup(
    name='demo',
    version='0.0.1',
    packages=['demo'], # 这里是源代码目录的名字,相对应
)

配置文件

简单来说就是Python代码,默认的配置写在default_settings.py中。

### demo/default_settings.py

DEBUG = True

# server-side session
SESSION_REDIS = 'redis://localhost/0'

我们根据环境变量指定。

### demo/__init__.py

if 'QK_CONFIG' in os.environ:
    _config_file = os.environ.get('QK_CONFIG')
    self.config.from_envvar(_config_file, silent=True)

在指定配置时,使用

$ QK_CONFIG="/path/to/config.prod.py" ve python ...

数据库配置

配置和 Flask 的原始配置相当

### default_settings.py

SQLALCHEMY_DATABASE_URL = 'sqlite3:////tmp/demo.db'

SQLALCHEMY_BINDS = {
  'default': 'sqlite3:////tmp/demo.db'
  'another': 'sqlite3:////tmp/another.db'
}

针对 MySQL 数据库,我们推荐使用这个连接器

配置相应的

### default_settings.py

SQLALCHEMY_DATABSE_URL = 'mysql+mysqldb://user:pass@host:3306/demo'

SQLALCHEMY_BINDS = {
  'default': 'mysql+mysqldb://user:pass@host:3306/demo'
  'another': 'mysql+mysqldb://user:pass@host:3306/another'
}

使用数据库

可以和原生 Flask-SQLAlchemy 一致的用法

### demo/views/demo.py

from demo import db

@app.route('/demo')
def demo():
    rs = db.session.execute('SELECT * FROM demo')

    for row in rs.fetchall():
    	# ...

当使用多个数据源时

with db.use_bind('another'):
    db.session.execute('...')

数据模型反射与使用

与 Flask-SQLAlchemy 中提供的 Model.query 方法不同。

这里相当于原生 SQLAlchemy 的 query 写法。

# 查询
Model = db.model('table_name', 'bind_name')

with db.use_bind('bind_name'):
    db.session.query(Model).filter_by(...)

# 添加

row = Model()
row.name = '...'
with db.use_bind('bind_name'):
    db.session.add(row)
    db.session.commit()

# 更新
row = db.session.query(Model).get(id)
row.name = '...'
db.session.commit()

资源文件管道

概念类似 Rails pipeline 一样。主要目的在于

  • 将第三方资源文件源代码隔离在自己的源代码之外,在运行、部署的时候获取
  • 有助于第三方资源的版本管理
  • 可以选择性的将资源文件打包,让单独页面只加载需要的资源

本功能基于 Flask-Assetswebassets ,并配合 Bower 使用。

例如我们希望在项目中使用 Bootstrap 与 jQuery。使用 Bower 我们需要有 NodeJS 环境。

$ [proxychains] npm install bower
$ [proxychains] ./ne bower init
$ [proxychains] ./ne bower install --save boostrap jquery

两者的源代码分别位于

  • bower_components/jquery/dist/jquery.js
  • bower_components/bootstrap/dist/css/bootstrap.css
  • bower_components/bootstrap/dist/js/bootstrap.js

首先需要注册资源文件,我们约定全局的在 views/__init__.py 中,而每个页面在各自的控制器中(例如 views/index.py )。

### views/__init__.py

from demo import app

app.register_asset('site.js', 'jquery/dist/jquery.js')
app.register_asset('site.css', 'bootstrap/dist/css/bootstrap.css', 'common.css')
### views/index.py

# ...

app.register_asset('index.js', 'index.js')

:默认寻找资源文件在 templates 目录下,初始化时我们把 bower_components_folder 也加入其中。

在页面上使用时:

### templates/layouts/common.html.jinja


{% assets "site.css" %}{% endassets %}
{% assets "jquery.js" %}{% endassets %}

对于浏览器中JavaScript执行依赖模型,我们还可以引入 RquireJS 来解决这个问题。

__END__