2011-06-28 247 views
21

我用于在Django和gunicorn上开发Web应用程序。如何在Pyramid应用程序启动时间获取注册表()。设置?

在Django的情况下,Django应用程序中的任何应用程序模块都可以通过django.conf.settings获得部署设置。 “settings.py”是用Python编写的,所以任何设置和预处理都可以动态定义

在gunicorn的情况下,有优先顺序的三个配置的地方,和一个设置注册表类实例相结合的。(但通常仅用于gunicorn不应用这些设置。)

  1. 命令行参数。
  2. 配置文件。 (如Django,编写于 Python,它可以有任意的 设置动态。)
  3. Paster应用程序设置。

在金字塔的情况下,根据金字塔文档,部署设置通常可以投入pyramid.registry.Registry()。设置。但它似乎只在存在pyramid.router.Router()实例时才被访问。 这是pyramid.threadlocal.get_current_registry()。设置返回None,在应用程序“main.py”的启动过程中。

例如,我通常在SQLAlchemy模型模块中定义一些业务逻辑,这需要部署设置如下。

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) 

但是, “设置[ 'external_api_endpoint']” 引发一个TypeError异常,因为 “设置” 莫属。

我想到了两种解决方案。

  • 定义一个可调用的,其接受在“models.py”和“main.py”,“配置”的说法用 配置()实例调用它。

    myapp/models.py

    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 
    
  • 或者,换一个空模块 “应用程序/ settings.py”,并把后来设置了进去。

    myapp/__init__.py

    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

    定义,因为发展的粗略设置。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']})) 
    

然后,其他模块可以通过 “进口myapp.settings” 获得任意部署设置。 或者,如果Registry()。设置优于“settings.py”,** settings kwargs和“settings.py”可以在“main.py”启动过程中结合并注册到Registry()。设置中。

无论如何,如何在启动时间获取设置dictionay?或者,金字塔轻轻地强迫我们将需要部署设置的每个代码放在“视图”可调参数中,这可以通过request.registry.settings随时获取设置字典?


编辑

谢谢,迈克尔和克里斯。

我终于明白为什么金字塔使用threadlocal变量(注册表和请求),特别是多个金字塔应用程序的注册表对象。

但是,在我看来,部署设置通常会影响可能定义特定应用程序的业务逻辑。这些逻辑通常放在一个或多个Python模块中,该模块可能不同于可轻松访问Config()或Registry()的“app/init .py”或“app/views.py”。 Python进程级别的Python模块通常是“全局”的。

也就是说,即使有多个金字塔应用程序共存,尽管它们有自己的threadlocal变量,但它们必须在Python进程级别共享那些可能包含特定于应用程序的somethings的“全局”Python模块。

因此,每个模块都可以通过应用程序“main”可调用或通过Registory()或Request()对象通过如此长的函数系列调用Configurator()来初始化callalbe通话可以满足通常的要求。但是,我猜金字塔的起源者(像我一样)或者开发者“拥有大量应用程序或许多设置”可能会感到麻烦,尽管这是金字塔设计。因此,我认为,Registry()。设置应该只有真正的“线程本地”变量,并且不应该具有正常的业务逻辑设置。开发人员应负责分离多个特定于应用程序的模块,类,可调用变量等。 截至目前,从我的观点来看,我会拿克里斯的答案。或者在“main”中调用,执行“execfile('settings.py',settings,settings)”并将其放入一些“全局”空间。

回答

16

另一种选择是,如果您喜欢通过Python进行全局配置,请创建settings.py文件。如果从ini文件中需要的值,解析ini文件,并抓住他们了(在模块范围内,所以在导入时运行):

from paste.deploy.loadwsgi import appconfig 
config = appconfig('config:development.ini', 'myapp', relative_to='.') 

if config['env'] == 'production': 
    api_endpoint_uri = 'http://api.external.com/?{0}' 
    timezone = timezone('US/Eastern') 
# .. and so on ... 

“的配置:development.ini”是ini中的名称文件(以'config:'为前缀)。 'myapp'是代表您的应用的配置文件中的部分名称(例如[app:myapp])。 “relative_to”是可以在其中找到配置文件的目录名称。

+0

谢谢!我接受你的解决方案。原因在上面描述了“编辑”部分(请允许我编辑,因为 详细描述) – takaomag

13

我使用的模式是将Configurator传递给需要初始化的模块。金字塔不使用任何全局变量,因为设计目标是能够在同一个进程中运行金字塔的多个实例。 threadlocals是全局的,但它们对当前请求是本地的,所以不同的Pyramid应用程序可以同时从不同的线程推送给它们。

记住这一点,如果你确实想要一个全局设置字典,你必须自己照顾。您甚至可以通过调用config.begin()将注册表推送到线程本地管理器。

我认为这里要做的主要事情是,您不应该在模块级别调用get_current_registry(),因为在导入时您并不确保线程定位被初始化,但是在您的init_model()函数中如果你打电话给get_current_registry(),如果你以前叫config.begin(),你会没事的。

抱歉,这有点令人费解,但它是一个常见的问题,最好的答案是:通过配置程序到你的子模块需要它,并让他们的东西添加到注册表/设置的对象供以后使用

+0

谢谢你的回答。从我的观点来看,克里斯的回答是可取的。原因如上所述“编辑”部分(请允许我编辑,因为长描述 – takaomag

+0

您能否解释将Configurator传递给模块更进一步?如何将它传递给我的models.py? – GhotiPhud

+3

推荐的方法扩展金字塔应用程序是通过'config.include'机制来调用外部方法并将其传递给配置对象。这是吸引所有模块并允许它们在启动时自行配置的好方法。 –

1

金字塔使用PasteDeploy进行静态配置,与Django不同。 你的[编辑]部分是一个很好的解决方案,我认为金字塔社区应该考虑这种用法。

相关问题