21

私は、Django と gunicorn で Web アプリケーションを開発するのに慣れています。

Django の場合、Django アプリケーション内のすべてのアプリケーション モジュールは、django.conf.settingsを介してデプロイメント設定を取得できます。「settings.py」は Python で記述されているため、任意の設定と前処理を動的に定義できます。

gunicorn の場合、優先順に 3 つの設定場所があり、1 つの設定レジストリ クラス インスタンスがそれらを組み合わせます (ただし、通常、これらの設定はアプリケーションではなく gunicorn のみに使用されます)。

  1. コマンド ライン パラメータ。
  2. 構成ファイル。(動的に任意の設定を持つことができる Python で書かれた Django のように。)
  3. 貼り付けアプリケーションの設定。

Pyramid の場合、Pyramid のドキュメントによると、デプロイメント設定は通常、pyramid.registry.Registry().settingsに入れることができます。しかし、pyramid.router.Router()インスタンスが存在する場合にのみアクセスされるようです。つまり、アプリケーション「main.py」の起動プロセス中に、pyramid.threadlocal.get_current_registry().settings は 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)

ただし、「settings['external_api_endpoint']」は、「settings」が None であるため、TypeError 例外を発生させます。

私は2つの解決策を考えました。

  • 「models.py」で「config」引数を受け入れる callable を定義し、「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
    
  • または、空のモジュール「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()
    

どちらのソリューションも要件を満たしていますが、面倒に感じます。私が欲しいのは以下です。

  • 開発.ini

    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']}))
    

その後、他のモジュールは「import myapp.settings」を介して任意の展開設定を取得できます。または、"settings.py" よりも Registry().settings の方が望ましい場合は、**settings kwargs と "settings.py" を組み合わせて、"main.py" の起動プロセス中に Registry().settings に登録することができます。

とにかく、起動時に設定辞書を取得する方法は?または、Pyramid は、デプロイ設定を必要とするすべてのコードを、 request.registry.settingsを通じていつでも設定辞書を取得できる「ビュー」callable に配置するように優しく強制しますか?


編集

ありがとう、マイケルとクリス。

Pyramid がスレッドローカル変数 (レジストリとリクエスト)、特に複数の Pyramid アプリケーションのレジストリ オブジェクトを使用する理由がようやくわかりました。

ただし、私の意見では、展開設定は通常、アプリケーション固有のものを定義するビジネス ロジックに影響を与えます。これらのロジックは通常、Config() または Registry() に簡単にアクセスできる「app/ init .py」または「app/views.py」以外の 1 つ以上の Python モジュールに配置されます。これらの Python モジュールは通常、Python プロセス レベルで「グローバル」です。

つまり、複数の Pyramid アプリケーションが共存する場合でも、独自のスレッドローカル変数にもかかわらず、それらは Python プロセス レベルでアプリケーション固有のものを含む可能性のある「グローバル」Python モジュールを共有する必要があります。

当然のことながら、これらのモジュールはすべて、アプリケーションの「メイン」呼び出し可能によって Configurator() で呼び出される「initialize()」callalbe を持つことができます。要件。しかし、Pyramid の設計とはいえ、Pyramid の初心者 (私のような) や、「アプリケーションが大きい、または設定が非常に多い」開発者は、面倒に感じるかもしれません。

したがって、Registry().settings は実際の「スレッドローカル」変数のみを持つべきであり、通常のビジネス ロジック設定を持つべきではないと思います。複数のアプリケーション固有のモジュール、クラス、callables 変数などを分離する責任は、開発者が負う必要があります。今のところ、私の観点から、クリスの答えを取り上げます。または、「メイン」呼び出し可能で、「execfile('settings.py', settings, settings)」を実行し、「グローバル」スペースに配置します。

4

3 に答える 3

17

別のオプションとして、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 ...

「config:development.ini」は、iniファイルの名前です(接頭辞「config:」が付いています)。'myapp'は、アプリを表す構成ファイルのセクション名です([app:myapp]など)。「relative_to」は、構成ファイルを見つけることができるディレクトリ名です。

于 2011-06-29T08:29:33.567 に答える
13

私が使用するパターンは、Configurator初期化が必要なモジュールに を渡すことです。設計目標は Pyramid の複数のインスタンスを同じプロセスで実行できるようにすることであるため、Pyramid はグローバル変数を使用しません。スレッドローカルはグローバルですが、現在のリクエストに対してローカルであるため、異なる Pyramid アプリが異なるスレッドから同時にそれらにプッシュできます。

これを念頭に置いて、グローバル設定ディクショナリが必要な場合は、自分で処理する必要があります。を呼び出して、自分でレジストリをスレッドローカル マネージャーにプッシュすることもできますconfig.begin()

ここで重要なことは、モジュール レベルで呼び出すべきではないということだと思います。get_current_registry()インポート時に、スレッドローカルが初期化されていることが実際には保証されていないためです。以前に電話した場合は問題ありません。init_model()get_current_registry()config.begin()

申し訳ありませんが、これは少し複雑ですが、よくある質問であり、最良の答えは次のとおりです。コンフィギュレーターを必要とするサブモジュールに渡し、後で使用するためにレジストリ/設定オブジェクトに追加できるようにします

于 2011-06-29T08:06:38.290 に答える
1

Pyramid は、Django とは異なり、PasteDeploy による静的構成を使用します。あなたの [EDIT] 部分は素晴らしい解決策です。Pyramid コミュニティはそのような使用法を検討すべきだと思います。

于 2011-08-05T12:03:52.110 に答える