私は、Django と gunicorn で Web アプリケーションを開発するのに慣れています。
Django の場合、Django アプリケーション内のすべてのアプリケーション モジュールは、django.conf.settingsを介してデプロイメント設定を取得できます。「settings.py」は Python で記述されているため、任意の設定と前処理を動的に定義できます。
gunicorn の場合、優先順に 3 つの設定場所があり、1 つの設定レジストリ クラス インスタンスがそれらを組み合わせます (ただし、通常、これらの設定はアプリケーションではなく gunicorn のみに使用されます)。
- コマンド ライン パラメータ。
- 構成ファイル。(動的に任意の設定を持つことができる Python で書かれた Django のように。)
- 貼り付けアプリケーションの設定。
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)」を実行し、「グローバル」スペースに配置します。