Python 如何在金字塔应用程序启动期间获取注册表()设置?
我习惯于在Django和gunicorn上开发web应用程序 对于Django,Django应用程序中的任何应用程序模块都可以通过Django.conf.settings获得部署设置。“settings.py”是用Python编写的,因此可以动态地定义任意设置和预处理 对于gunicorn,它有三个按优先顺序排列的配置位置,一个设置注册表类实例组合了这些位置。(但通常这些设置仅用于gunicorn而不是应用程序。)Python 如何在金字塔应用程序启动期间获取注册表()设置?,python,paste,pyramid,Python,Paste,Pyramid,我习惯于在Django和gunicorn上开发web应用程序 对于Django,Django应用程序中的任何应用程序模块都可以通过Django.conf.settings获得部署设置。“settings.py”是用Python编写的,因此可以动态地定义任意设置和预处理 对于gunicorn,它有三个按优先顺序排列的配置位置,一个设置注册表类实例组合了这些位置。(但通常这些设置仅用于gunicorn而不是应用程序。) 命令行参数 配置文件。(像Django,用英文写的) Python,它可以有任意
myapp/models.py
from sqlalchemy import Table, Column, Types
from sqlalchemy.orm import mapper
from pyramid.threadlocal import get_current_registry
from myapp.db import session, metadata
settings = get_current_registry().settings
mytable = Table('mytable', metadata,
Column('id', Types.INTEGER, primary_key=True,)
(other columns)...
)
class MyModel(object):
query = session.query_property()
external_api_endpoint = settings['external_api_uri']
timezone = settings['timezone']
def get_api_result(self):
(interact with external api ...)
mapper(MyModel, mytable)
from sqlalchemy import Table, Column, Types
from sqlalchemy.orm import mapper
from myapp.db import session, metadata
_g = globals()
def initialize(config):
settings = config.get_settings()
mytable = Table('mytable', metadata,
Column('id', Types.INTEGER, rimary_key = True,)
(other columns ...)
)
class MyModel(object):
query = session.query_property()
external_api_endpoint = settings['external_api_endpoint']
def get_api_result(self):
(interact with external api)...
mapper(MyModel, mytable)
_g['MyModel'] = MyModel
_g['mytable'] = mytable
from pyramid.config import Configurator
from .resources import RootResource
def main(global_config, **settings):
config = Configurator(
settings = settings,
root_factory = RootResource,
)
import myapp.settings
myapp.setting.settings = config.get_settings()
(other configurations ...)
return config.make_wsgi_app()
但是,“settings['external_api_endpoint']”会引发TypeError异常,因为“settings”是None
我想到了两个解决办法
- 定义一个可调用函数,它接受“models.py”中的“config”参数,“main.py”使用
Configurator()实例
myapp/models.py
from sqlalchemy import Table, Column, Types from sqlalchemy.orm import mapper from pyramid.threadlocal import get_current_registry from myapp.db import session, metadata settings = get_current_registry().settings mytable = Table('mytable', metadata, Column('id', Types.INTEGER, primary_key=True,) (other columns)... ) class MyModel(object): query = session.query_property() external_api_endpoint = settings['external_api_uri'] timezone = settings['timezone'] def get_api_result(self): (interact with external api ...) mapper(MyModel, mytable)
from sqlalchemy import Table, Column, Types from sqlalchemy.orm import mapper from myapp.db import session, metadata _g = globals() def initialize(config): settings = config.get_settings() mytable = Table('mytable', metadata, Column('id', Types.INTEGER, rimary_key = True,) (other columns ...) ) class MyModel(object): query = session.query_property() external_api_endpoint = settings['external_api_endpoint'] def get_api_result(self): (interact with external api)... mapper(MyModel, mytable) _g['MyModel'] = MyModel _g['mytable'] = mytable
from pyramid.config import Configurator from .resources import RootResource def main(global_config, **settings): config = Configurator( settings = settings, root_factory = RootResource, ) import myapp.settings myapp.setting.settings = config.get_settings() (other configurations ...) return config.make_wsgi_app()
- 或者,放置一个空模块“app/settings.py”,稍后将设置放入其中
myapp/\uuuuu init\uuuuuuuuuuy.py
from sqlalchemy import Table, Column, Types from sqlalchemy.orm import mapper from pyramid.threadlocal import get_current_registry from myapp.db import session, metadata settings = get_current_registry().settings mytable = Table('mytable', metadata, Column('id', Types.INTEGER, primary_key=True,) (other columns)... ) class MyModel(object): query = session.query_property() external_api_endpoint = settings['external_api_uri'] timezone = settings['timezone'] def get_api_result(self): (interact with external api ...) mapper(MyModel, mytable)
from sqlalchemy import Table, Column, Types from sqlalchemy.orm import mapper from myapp.db import session, metadata _g = globals() def initialize(config): settings = config.get_settings() mytable = Table('mytable', metadata, Column('id', Types.INTEGER, rimary_key = True,) (other columns ...) ) class MyModel(object): query = session.query_property() external_api_endpoint = settings['external_api_endpoint'] def get_api_result(self): (interact with external api)... mapper(MyModel, mytable) _g['MyModel'] = MyModel _g['mytable'] = mytable
from pyramid.config import Configurator from .resources import RootResource def main(global_config, **settings): config = Configurator( settings = settings, root_factory = RootResource, ) import myapp.settings myapp.setting.settings = config.get_settings() (other configurations ...) return config.make_wsgi_app()
- 发展网
定义粗略设置,因为development.ini只能有字符串类型常量
[app:myapp] use = egg:myapp env = dev0 api_signature = xxxxxx
- myapp/settings.py
基于development.ini定义详细设置,因为可以设置任何任意变量(类型)
import datetime, urllib from pytz import timezone from pyramid.threadlocal import get_current_registry pyramid_settings = get_current_registry().settings if pyramid_settings['env'] == 'production': api_endpoint_uri = 'http://api.external.com/?{0}' timezone = timezone('US/Eastern') elif pyramid_settings['env'] == 'dev0': api_endpoint_uri = 'http://sandbox0.external.com/?{0}' timezone = timezone('Australia/Sydney') elif pyramid_settings['env'] == 'dev1': api_endpoint_uri = 'http://sandbox1.external.com/?{0}' timezone = timezone('JP/Tokyo') api_endpoint_uri = api_endpoint_uri.format(urllib.urlencode({'signature':pyramid_settings['api_signature']}))
编辑 谢谢,迈克尔和克里斯 我终于明白了为什么Pyramid使用threadlocal变量(注册表和请求),特别是注册表对象用于多个Pyramid应用程序 然而,在我看来,部署设置通常会影响业务逻辑,这些逻辑可能会定义特定于应用程序的东西。这些逻辑通常放在一个或多个Python模块中,这些模块可能不是“app/init.py”或“app/views.py”,它们可以轻松访问Config()或Registry()。这些Python模块通常是Python进程级别的“全局”模块 也就是说,即使多个金字塔应用程序共存,尽管它们有自己的threadlocal变量,它们也必须共享那些“全局”Python模块,这些模块可能在Python进程级别包含特定于应用程序的东西 当然,每个模块都可以有“initialize()”callalbe,它由应用程序“main”调用的Configurator()调用,或者通过长系列的函数调用传递registry()或Request()对象,这样就可以满足通常的要求。但是,我想金字塔的创始人(像我一样)或拥有“大型应用程序或这么多设置”的开发人员可能会感到麻烦,尽管这是金字塔设计 因此,我认为Registry()设置应该只有真正的“线程本地”变量,而不应该有正常的业务逻辑设置。开发人员应负责分离多个特定于应用程序的模块、类、可调用变量等。
现在,从我的观点来看,我将接受克里斯的回答。或者在“main”可调用中,执行“execfile('settings.py',settings,settings)”,并将其放在一些“全局”空间中。我使用的模式是将
配置程序传递给需要初始化的模块。Pyramid不使用任何全局变量,因为设计目标是能够在同一进程中运行Pyramid的多个实例。threadlocals是全局的,但它们是当前请求的本地,因此不同的金字塔应用程序可以从不同的线程同时推送到它们
记住这一点,如果你真的想要一个全局设置字典,你必须自己处理。您甚至可以通过调用config.begin()
将注册表推送到threadlocal管理器上
我认为这里需要注意的主要一点是,您不应该在模块级别调用get\u current\u registry()
,因为在导入时,您并不能真正保证线程局部变量已初始化,但是如果您调用get\u current\u registry()
,则在init\u model()
函数中,如果您以前调用了config.begin()
,您就可以了
抱歉,这有点复杂,但这是一个常见的问题,最好的答案是:将配置程序传递给需要它的子模块,并允许它们将内容添加到注册表/设置对象以供以后使用另一个选项,如果您喜欢通过Python进行全局配置,请创建一个settings.py文件。如果它需要ini文件中的值,则解析ini文件并将其取出(在模块范围内,因此它在导入时运行):
“config:development.ini”是ini文件的名称(前缀为“c