Python 如何在金字塔应用程序启动期间获取注册表()设置?

Python 如何在金字塔应用程序启动期间获取注册表()设置?,python,paste,pyramid,Python,Paste,Pyramid,我习惯于在Django和gunicorn上开发web应用程序 对于Django,Django应用程序中的任何应用程序模块都可以通过Django.conf.settings获得部署设置。“settings.py”是用Python编写的,因此可以动态地定义任意设置和预处理 对于gunicorn,它有三个按优先顺序排列的配置位置,一个设置注册表类实例组合了这些位置。(但通常这些设置仅用于gunicorn而不是应用程序。) 命令行参数 配置文件。(像Django,用英文写的) Python,它可以有任意

我习惯于在Django和gunicorn上开发web应用程序

对于Django,Django应用程序中的任何应用程序模块都可以通过Django.conf.settings获得部署设置。“settings.py”是用Python编写的,因此可以动态地定义任意设置和预处理

对于gunicorn,它有三个按优先顺序排列的配置位置,一个设置注册表类实例组合了这些位置。(但通常这些设置仅用于gunicorn而不是应用程序。)

  • 命令行参数
  • 配置文件。(像Django,用英文写的) Python,它可以有任意 设置动态设置
  • 粘贴应用程序设置
  • 对于金字塔,根据金字塔文档,部署设置通常可以放入Pyramid.registry.registry().settings中。但似乎只有在存在pyramid.router.router()实例时才能访问它。 即pyramid.threadlocal.get_current_registry()。在应用程序“main.py”的启动过程中,设置将返回None

    例如,我通常在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)
    
    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']}))
      
    然后,其他模块可以通过“导入myapp.settings”获取任意部署设置。 或者,如果Registry().settings优于“settings.py”,则在“main.py”启动过程中,**settings kwargs和“settings.py”可以组合并注册到Registry().settings中

    无论如何,如何在启动时获取设置词汇?或者,Pyramid温和地迫使我们将需要部署设置的所有代码放入“视图”可调用项中,这些可调用项可以随时通过request.registry.settings获取设置词典


    编辑

    谢谢,迈克尔和克里斯

    我终于明白了为什么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