tak*_*mag 21 python paste pyramid
我习惯在Django和gunicorn上开发Web应用程序.
对于Django,Django应用程序中的任何应用程序模块都可以通过django.conf.settings获取部署设置."settings.py"是用Python编写的,因此可以动态定义任意设置和预处理.
在gunicorn的情况下,它按优先顺序有三个配置位置,并且一个设置注册表类实例组合这些.(但通常这些设置仅用于gunicorn而不是应用程序.)
对于Pyramid,根据Pyramid文档,部署设置通常可以放入pyramid.registry.Registry().settings中.但它似乎仅在存在pyramid.router.Router()实例时才被访问.那就是pyramid.threadlocal.get_current_registry().settings在应用程序"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)
Run Code Online (Sandbox Code Playgroud)
但是,"settings ['external_api_endpoint']"会引发TypeError异常,因为"settings"为None.
我想了两个解决方案.
定义一个callable,它接受"models.py"中的"config"参数,"main.py"使用Configurator()实例调用它.
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
Run Code Online (Sandbox Code Playgroud)或者,将一个空模块"app/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()
Run Code Online (Sandbox Code Playgroud)两种解决方案都符合要求,但我觉得很麻烦.我想要的是以下内容.
development.ini
定义粗略设置,因为development.ini只能有字符串类型常量.
[app:myapp]
use = egg:myapp
env = dev0
api_signature = xxxxxx
Run Code Online (Sandbox Code Playgroud)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']}))
Run Code Online (Sandbox Code Playgroud)然后,其他模块可以通过"import myapp.settings"获得任意部署设置.或者,如果Registry().设置优于"settings.py",**设置kwargs和"settings.py"可以组合并在"main.py"启动过程中注册到Registry().settings中.
无论如何,如何在启动时获取设置词典?或者,Pyramid会轻轻地强制我们将需要部署设置的每个代码放在"views"callables中,这些代码可以通过request.registry.settings随时获取设置字典?
编辑
谢谢,迈克尔和克里斯.
我终于理解为什么Pyramid使用threadlocal变量(注册表和请求),特别是多个Pyramid应用程序的注册表对象.
但是,在我看来,部署设置通常会影响可能定义特定于应用程序的事物的业务逻辑.这些逻辑通常放在一个或多个Python模块中,这些模块可能不是"app/init .py"或"app/views.py",可以轻松访问Config()或Registry().那些Python模块通常在Python进程级别是"全局的".
也就是说,即使不止一个Pyramid应用程序共存,尽管它们有自己的threadlocal变量,但它们必须共享那些可能在Python进程级别包含特定应用程序的"全局"Python模块.
当然,每个模块都可以有"initialize()"callalbe,它由应用程序"main"可调用的Configurator()调用,或通过Registory()或Request()对象通过如此长的一系列函数调用可以满足通常要求.但是,我猜金字塔开头(像我一样)或开发人员有"大应用程序或许多设置"可能会觉得麻烦,虽然那是金字塔设计.
因此,我认为,Registry().设置应该只有真正的"线程局部"变量,并且不应该具有正常的业务逻辑设置.开发人员应该对多个特定于应用程序的模块,类,可调用变量等的隔离负责.截至目前,从我的观点来看,我将采取克里斯的答案.或者在"main"可调用中,执行"execfile('settings.py',settings,settings)"并将其放在某个"全局"空间中.
Chr*_*ugh 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 ...
Run Code Online (Sandbox Code Playgroud)
'config:development.ini'是ini文件的名称(前缀为'config:').'myapp'是配置文件中代表您的应用的部分名称(例如[app:myapp])."relative_to"是可以在其中找到配置文件的目录名称.
Mic*_*kel 13
我使用的模式是传递Configurator给需要初始化的模块.Pyramid不使用任何全局变量,因为设计目标是能够在同一进程中运行Pyramid的多个实例.threadlocals是全局的,但它们是当前请求的本地,因此不同的Pyramid应用程序可以同时从不同的线程推送到它们.
考虑到这一点,如果你想要一个全局设置词典,你将不得不自己处理.您甚至可以通过调用将注册表推送到threadlocal管理器config.begin().
我认为这里最重要的一点就是你不应该get_current_registry()在模块级别调用,因为在导入时你并不能保证threadlocals被初始化,但是init_model()如果你打电话get_current_registry(),你的函数就是你的'如果你以前打过电话,那就好了config.begin().
对不起,这有点令人费解,但这是一个常见的问题,最好的答案是:将配置程序传递给需要它的子模块,并允许它们将内容添加到注册表/设置对象中以供日后使用.
| 归档时间: |
|
| 查看次数: |
7830 次 |
| 最近记录: |