2011-06-28 135 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不同。 你的[編輯]部分是一個很好的解決方案,我認爲金字塔社區應該考慮這種用法。

相關問題