Settings说明¶
加载顺序¶
在Uliweb中,配置信息一般是放在settings.ini文件中的,目前有以下几个级别的settings.ini 信息:
default_settings.ini
apps/
app/settings.ini
settings.ini
local_settings.ini
从上往下看,我们可以看到有缺省的settings信息,也有app级别的settings信息,还有整 个项目的settings信息,最后是项目的本地settings信息。它们的加载顺序是从上到下。 对于app下的 settings.ini文件,它会按照app在 INSTALLED_APPS
中的定义顺序来处理。
同名变量处理与强制替换¶
因此,后加载的项一旦发现有重名的情况,会进行以下特殊的处理:
- 如果值为list, dict, set,则进行合并处理,即对于list,执行extend(),对于dict 执行update,同时如果dict的值为dict或list,则会进行递归合并处理。
- 如果是其它的值,则进行替換,即后面定义的值覆盖前面定义的值
如果写法为:
name <= value
则不管value是什么都将进行替換。
基本格式¶
settings.ini的写法是类ini格式,但是和标准的ini有所区别:
基本写法是:
[section] name = value
- section
节的名字,它应该是一个合法的标识符,即开始为字母或
_
,后续可 以是字母或_
或数字。大小写敏感。- name
key,不应包含 '=',可以不是标识符。
name不能与Ini初始化时传入的env中的key重名,如果有会报错。比如不能是
set
, 因为set
是作为内置类型在初始化时自动添加到 env 中的。- value
值,并且是符合python语法的,因此你可以写list, dict, tuple, 三重字符串和 其它的标准的python的类型。可以在符合python语法的情况下占多行。也可以是简单 的表达式。
- 不支持多级,只支持两级处理
- 注释写法是第一列为
'#'
- 可以在文件头定义
#coding=utf-8
来声明此文件的编码,以便可以使用u'中文'
这样的内容。 - 可以使用
_('English')
这样的翻译字符串
settings中的value只能定义基本的 Python 数据结构和表达式,因为它们将使用 eval 来 执行,所以不能随意写代码,也不能导入其它的模块。在uliweb启动时,将自动向settings 中注入特殊变量,如:
_
此为翻译函数set
集合type
这些是可以直接使用的。
国际化支持¶
可以直接在settings中使用 _
进行语言的翻译。注意应使用在value部分。例如:
[DEFAULT]
Project = _('Project')
在需要进行翻译时,使用 i18n
命令可以自将settings.ini中的翻译串提取出来。
配置项引用¶
在定义 value ,我们可以直接引入前面已经定义好的配置项,有两种类型:
section内部引用,即引用的配置项是在同一节中当前配置项之前定义的其它的项,如:
[DEFAULT] a = 'http://abc.com' b = a + '/index'
一个section内部引用,直接在value部分写对应的配置项名称即可。但是要注意,因为 key并不要求一定是标识符,所以,如果key的定义不是标识符,则直接引用的话,可能 会因为eval执行时出错。这样就要使用第二种方法。
跨section引用。它需要在配置项前面添加所在的section的名称,如:
[DEFAULT] a = 'http://abc.com' [OTHER] b = DEFAULT.a + '/index' c = DEFAULT['a'] + '/index' d = OTHER.b + '/test'
上面示例中,
b
引用了DEFAULT
中的配置项。c
是采用dict下标的写法,适 用于key不是标识符的情况。d
则是以添加section名字的方式来实现section内部 引用。
字符串引用扩展¶
引用方式一般是为了解决某个值在多个配置项中重复出现,而采用的减化手段。一般可以 使用表达式的方法进行值的加工。如果是字符串,还可以直接在字符串中定义如 {{expr}}
这样的格式串来引用配置项的值。如:
[DEFAULT]
a = 'http://abc.com'
b = '{{DEFAULT.a}}/index'
在 {{}}
内的值会自动被替換为相应的配置项的值。这样有时写起来比表达式可能更方便。
环境变量的引用扩展¶
有时需要在配置中引入一些环境变量,如很多云环境都是把数据库等的参数放在环境变量 中。因此,如果你需要在配置文件中引入这些变量,可以使用:
a = '$MYSQL_HOST'
a = '${MYSQL_HOST}:$MYSQL_PORT'
a = $MYSQL_PORT
两种用法没有什么区别。只不过 ${}
可以更好的区分变量后面是英文字母的情况。
预设值的替换¶
目前主要是用于在值中替换为当前app的名字,如在 uliweb.contrib.auth
下的 settings.ini
, 以下的内容:
user = '#{appname}.models.User'
将被替换为:
user = 'uliweb.contrib.auth.models.User'
其功能的目的主要是为了当移动app的目录时,减少配置中对appname的硬编码。
settings的使用¶
settings在读取后会生成一个对象,要先获得这个对象再使用它。获取settings对象可以 根据不同的场景,使用不同的方法:
web环境中,如果是在view函数中进行处理,则直接可以使用settings对象。如:
@expose('/index') def index(): return str(settings)
因为uliweb会自动向所有的view函数注入settings对象,所以可以直接使用。
命令行或web环境中非view函数
最通用的做法,可以在需要使用settings的代码中通过导入来使用settings对象,如:
from uliweb import settings
那么建议是在函数内部导入,不要写在模板顶层。这样确保settings在使用时一定被 创建好了。uliweb会保证settings在创建时,是线程安全的。
有了settings对象,我们就可以调用它的方法和属性来引用配置文件中的各个值了。settings 对象,你可以理解为一个二级的字典或二级的对象树。如果key或section名都是标识符,通 常情况下使用 .
的属性引用方式就可以了,不然可以象字典一样使用下标或 get()
等 方法来使用。常见的使用方式有:
settings[section][key]
以字典的形式来处理settings.get_var('section/key', default=None)
这种形式可以写一个查找的路径的形式settings.section
或settings.section.key
以.
的形式来引用section和key,不过要求section和key是标识符,且不能是保留字。for k, v in settings.section.items()
可以把settings.section当成一个字典来使用,因此字典的许多方法都可以使用,如 in, has 之类的。
关于settings写入的说明¶
settings在设计时是希望可以读和写的。读大家很容易理解,但是写的作用是什么呢?
写的作用主要是方便一些工具的自动生成配置。因此在简单情况下, settings.save(fileobj)
是可以将当前的settings值保存到某个文件对象中去。
但是由于现在settings的值可以是一个表达式,并且,表达式可以包含变量;另外,由于 存在多个settings.ini文件,并且会对重名的变量名的可变值(list, dict, set)进行合 并处理,使得按原样保存变得困难。所以现在很少进行写入处理,如果要处理,则建议不 使用含变量的表达式,并且只处理一个文件,不处理多个文件。
关于Lazy的处理说明¶
Lazy的处理是在0.2版本中加入的,它是与配置项的引用有关。考虑以下场景:
某个app定义了一串配置项,如:
[PARA] domain = 'http://localhost:8000' login_url = domain + '/login'
- 然后当部署到某个环境中时,用户希望在local_settings.ini中覆盖上面的domain的值 为实际的地址。
这时会有这样的问题:在解析app的settings.ini文件时,domain的值已经解析出来了,因 此在处理login_url时,它的值也就固定下来了。等local_settings.ini再覆盖domain, login_url已经不会再重新计算了。
所以为了解决因为多个settings.ini按顺序导入,但是变量提前计算的问题,在0.2版本中 引入了Lazy的处理方式。即,在读取多个settings.ini时,并不计算配置项的值,只是放 到这个配置项对应的数组中,等全部读取完毕,由uliweb主动调用settings的freeze()方法 开始对所有未计算的值进行求值。通过这样的方法就延迟了求值的时间,保证了最终想到的 结果。
重要配置参数说明¶
以下按不同的节(section)来区分
GLOBAL¶
[GLOBAL]
DEBUG = False #是否当有异常时,输出调试页面
DEBUG_CONSOLE = False #是否在调试页面上显示console窗,用来输入代码
TEMPLATE_SUFFIX = '.html' #模板文件后缀
ERROR_PAGE = 'error' + TEMPLATE_SUFFIX #错误页面文件名
WSGI_MIDDLEWARES = [] #WSGI中间件
HTMLPAGE_ENCODING = 'utf-8' #页面文件编码
FILESYSTEM_ENCODING = None #文件系统编码,在linux上,建议进行相应的设置
DEFAULT_ENCODING = 'utf-8' #缺省编码
TIME_ZONE = None #时区设置
LOCAL_TIME_ZONE = None #本地时区
TEMPLATE_TEMPLATE = ('%(view_class)s/%(function)s', '%(function)s')
#不同view方法的模板路径形式,前者为类形式,
#后者为函数形式
TEMPLATE_DIRS = [] #全局的模板路径,当所有app中都找不到模板时,将在
#这个目录下进行查找
其中 TEMPLATE_TEMPLATE
用于对应不同的view形式的模板路径方式。对于类,缺省是 在templates下为 classname/function.html
的形式。而函数形式的view则直接对应 templates下的 function.html
。
LOG¶
详情参见 日志处理说明 。
FUNCTIONS¶
用于定义公共的一些函数,例如:
[FUNCTIONS]
flash = 'uliweb.contrib.flashmessage.flash'
在此定义之后,可以有以下两种引用形式:
from uliweb import function
flash = function('flash')
flash(message)
#或
from uliweb import functions
functions.flash(message)
DECORATORS¶
用于定义公共的一些decorator函数,类似于FUNCTIONS的使用方式,但是区分为全部是decorator。
使用形式为:
from uliweb import decorators
@decorators.check_role('superuser')
def index():
pass
BINDS¶
用于绑定某个信号的配置,例如:
[BINDS]
audit.post_save = 'post_save'
在配置中,每个绑定的函数应有一个名字,在最简单的情况下,可以省略名字,函数名就 与绑定名相同。
BINDS有三种定义形式:
function = topic #最简单情况,函数名与绑定名相同,topic是对应的信号
bind_name = topic, function #给出信号和函数路径
bind_name = topic, function, {kwargs} #给出信号,函数路径和参数(字典形式)
其中function中是函数路径,比如 appname.model.function_name
,例用这种形式,uliweb 可以根据 appname.model
来导入函数。
上面的 bind_name
没有特别的作用,只是要求唯一,一方面利用它可以实现:一个函数 可以同时处理多个 topic 的情况,只要定义不同的 bind_name
即可。另一方面,可以 起到替換的作用,如果某个绑定不想再继续使用或替换为其它的配置,可以写一个同名的 bind_name
让后面的替換前面的。
EXPOSES¶
用于配置URL,在一般情况下,你只要在views.py中定义 @expose(url)
即可,但是在复杂情况 下,特别是可以允许URL被替换的情况下,考虑把URL定义在settings.ini中,如:
[EXPOSES]
login = '/login', 'uliweb.contrib.auth.views.login'
logout = '/logout', 'uliweb.contrib.auth.views.logout'
URL在Uliweb中是可以给每个URL起个名字的,以便在反向获取时只使用这个名字,同时它也可以用来方便进行替換。
它也有三种定义方式,类似于BINDS的定义:
function = url #最简单情况,函数名与url名相同
url_name = url, function #给出url, 函数路径和url名
url_name = url, function, {kwargs} #给出url,函数路径,url名和参数(字典形式)
pyini模块¶
整个settings的处理都是由pyini模块来处理的。它存在于uliweb/utils目录下,在程序中 的使用如:
from uliweb.utils import pyini
x = pyini.Ini('inifile')
这样就可以打开一个ini文件。如果有多个ini文件要进行合并处理,则使用 read()
继续处理即可,如:
x.read('another.ini')
settings.ini文件可以保存,如:
x.save()