web-dev-qa-db-ja.com

Django

Django Projectsにいくつかの定数が必要です。たとえば、MIN_TIME_TESTという定数を考えてみましょう。

この定数には、私のPythonコード内から、および任意のテンプレート内から)の2か所でアクセスできるようにしたいと思います。

これを行うための最良の方法は何ですか?

EDIT:明確にするために、私はテンプレートコンテキストプロセッサと、settings.pyまたは他のファイルに物を入れてインポ​​ートすることについて知っています。

私の質問は、「Do n't Repeat Yourself」ルールに違反せずに、2つのアプローチをどのように組み合わせるかです。これまでの回答に基づいて、これが私のアプローチです。

定数のリスト(MIN_TIME_TEST = 5など)を含むglobal_constants.pyというファイルを作成したいと思います。このファイルを任意のモジュールにimportして、定数を取得できます。

しかし今、私はこれらすべての定数を返すコンテキストプロセッサを作成したいと思います。 John Meeの回答のように、辞書に再度リストすることなく、これを自動的に実行するにはどうすればよいですか?

19
Edan Maor

LuperとVladimirはどちらも正しいimhoですが、要件を満たすには両方が必要です。

  • 定数はsettings.pyにneedである必要はありませんが、どこにでも配置して、その場所からビュー/モデル/モジュールコードにインポートすることができます。グローバルに関連していると見なされることを気にしない場合は、それらを__init__.pyに入れることがあります。

  • このようなコンテキストプロセッサは、選択された変数がグローバルにテンプレートスコープ内にあることを保証します

    def settings(request):
        """
        Put selected settings variables into the default template context
        """
        from Django.conf import settings
        return {
            'DOMAIN':     settings.DOMAIN,
            'GOOGLEMAPS_API_KEY': settings.GOOGLEMAPS_API_KEY,
        }
    

しかし、Djangoを初めて使用する場合、これはやり過ぎかもしれません。おそらく、変数をテンプレートスコープに入れる方法を尋ねているだけです...?

from Django.conf import settings

...
# do stuff with settings.MIN_TIME_TEST as you wish

render_to_response("the_template.html", { 
    "MIN_TIME_TEST": settings.MIN_TIME_TEST 
}, context_instance=RequestContext(request)
17
John Mee

他の人の答えに基づいて構築するために、これを実装する簡単な方法は次のとおりです。

設定ファイル内:

GLOBAL_SETTINGS = {
    'MIN_TIME_TEST': 'blah',
    'RANDOM_GLOBAL_VAR': 'blah',
}

次に、 John Meeのコンテキストプロセッサ から構築します。

def settings(request):
    """
    Put selected settings variables into the default template context
    """
    from Django.conf import settings
    return settings.GLOBAL_SETTINGS

これにより、DRYの問題が解決されます。

または、グローバル設定をたまにしか使用せず、ビュー内から呼び出す場合は、次のようにします。

def view_func(request):
    from Django.conf import settings
    # function code here
    ctx = {} #context variables here
    ctx.update(settings.GLOBAL_SETTINGS)
    # whatever output you want here
6
Jordan Reiter

アプリケーションのsettings.pyに配置することを検討してください。もちろん、テンプレートで使用するには、他の通常の変数と同じようにテンプレートで使用できるようにする必要があります。

3
devmiles.com

コンテキストプロセッサは、より動的なオブジェクトデータの処理に適しています ドキュメント でマッピングとして定義されており、ここの多くの投稿では、変更されているか、ビューに渡されています--itたとえば、ビューで専用のコンテキストプロセッサを使用するのを忘れたために、テンプレートがグローバル情報にアクセスできなくなる可能性があることは意味がありません。データは定義上グローバルであり、ビューをテンプレートに結合します。

より良い方法は、カスタムテンプレートタグを定義することです。こちらです:

  • テンプレートは、グローバル情報を渡すためにビューに依存していません
  • それはDRY-erです:グローバル設定を定義するアプリは多くのプロジェクトにエクスポートでき、プロジェクト間で共通のコードを排除します
  • テンプレートは、ビュー機能ではなく、グローバル情報にアクセスできるかどうかを決定します

以下の例では、このMIN_TIME_TEST変数をロードするというあなたの問題と、環境が変化すると変化するURLをロードするという私がよく直面する問題を扱います。

私には4つの環境があります-2つの開発と2つの本番:

  • 開発:Django-Webサーバー、URL:localhost:8000
  • 開発:Apache Webサーバー:URL:sandbox.com-> 127.0.0.1に解決
  • 製品サンドボックスサーバー、URL:sandbox.domain.com
  • 製品サーバー:url:domain.com

私はすべてのプロジェクトでこれを行い、すべてのURLをファイルglobal_settings.pyに保持して、コードからアクセスできるようにします。任意のテンプレートに(オプションで)ロードできるカスタムテンプレートタグ{%site_url%}を定義します

Global_settingsというアプリを作成し、それが設定に含まれていることを確認します。INSTALLED_APPSタプル。

Djangoは、データの表示方法を指示するrender()メソッドを使用して、テンプレート化されたテキストをノードにコンパイルします。渡された名前に基づいてglobal_settings.pyに値を返すことにより、データをレンダリングするオブジェクトを作成しました。

次のようになります。

from Django import template
import global_settings

class GlobalSettingNode(template.Node):
    def __init__(self, settingname):
        self.settingname = settingname;
    def render(self, context):
        if hasattr(global_settings, self.settingname):
            return getattr(global_settings, self.settingname)
        else:
            raise template.TemplateSyntaxError('%s tag does not exist' % self.settingname)

ここで、global_settings.pyに、いくつかのタグを登録します。例の場合はsite_url、例の場合はmin_test_timeです。このように、テンプレートから{%min_time_test%}が呼び出されると、get_min_time_testが呼び出され、値= 5でロードされるように解決されます。私の例では、{%site_url%}が名前ベースのルックアップを実行するため、4つのURLをすべて一度に定義したままにして、使用する環境を選択できます。これは、Djangoの組み込みのsettings.Debug = True/Falseフラグを使用するよりも柔軟性があります。

from Django import template
from templatenodes import GlobalSettingNode
register = template.Library()


MIN_TIME_TEST = 5

DEV_Django_SITE_URL = 'http://localhost:8000/'
DEV_Apache_SITE_URL = 'http://sandbox.com/'
PROD_SANDBOX_URL = 'http://sandbox.domain.com/'
PROD_URL = 'http://domain.com/'

CURRENT_ENVIRONMENT = 'DEV_Django_SITE_URL'



def get_site_url(parser, token):
    return GlobalSettingNode(CURRENT_ENVIRONMENT)

def get_min_time_test(parser, token):
    return GlobalSettingNode('MIN_TIME_TEST')

register.tag('site_url', get_site_url)
register.tag('min_time_test', get_min_time_test)

これが機能するために、Djangoはglobal_settings.pyがpythonアプリの下のtemplatetagsと呼ばれるDjangoパッケージに配置されていることを期待していることに注意してください。ここでのDjangoアプリはglobal_settingsと呼ばれるため、ディレクトリ構造は次のようになります。

/project-name/global_settings/templatetags/global_settings.pyなど。

最後に、テンプレートはグローバル設定でロードするかどうかを選択します。これはパフォーマンスに役立ちます。この行をテンプレートに追加して、global_settings.pyに登録されているすべてのタグを公開します。

{% load global_settings %}

これで、MIN_TIME_TESTを必要とする他のプロジェクト、またはこれらの環境を公開するだけで、このアプリをインストールできます=)

2
Alan Illing

コンテキストプロセッサ を使用して、すべてのテンプレートで定数を使用できるようにします(settings.pyは、ウラジミールが言ったようにそれらを定義するのに最適な場所です)。

2
Luper Rouch

John Meeの最後の部分のバリエーションで、JordanReiterが説明しているのと同じアイデアについて少し詳しく説明しています。

ジョーダンが提案したものに似た何かが設定にあるとします。言い換えると、次のようなものです。

GLOBAL_SETTINGS = {
   'SOME_CONST': 'thingy',
   'SOME_OTHER_CONST': 'other_thingy',
}

さらに、テンプレートに渡したい変数のいくつかを含む辞書がすでにあるとします。おそらく、ビューに引数として渡されます。それをmy_dictと呼びましょう。 my_dictの値がsettings.GLOBAL_SETTINGSディクショナリの値をオーバーライドするとします。

あなたはあなたの見解で次のようなことをするかもしれません:

def my_view(request, *args, **kwargs)
    from Django.conf import settings
    my_dict = some_kind_of_arg_parsing(*args,**kwargs)
    tmp = settings.GLOBAL_SETTINGS.copy()
    tmp.update(my_dict)
    my_dict = tmp
    render_to_response('the_template.html', my_dict, context_instance=RequestContext(request))

これにより、設定をグローバルに決定し、テンプレートで使用できるようになり、各設定を手動で入力する必要がなくなります。

しないテンプレートを渡すための追加の変数がない場合、またはオーバーライドする必要がない場合は、次のようにすることができます。

render_to_response('the_template.html', settings.GLOBAL_SETTINGS, context_instance=RequestContext(request))

私がここで議論していることとジョーダンが持っていることの主な違いは、彼にとって、settings.GLOBAL_SETTINGSはあなたのコンテキスト辞書と共通しているものをすべてオーバーライドし、私の場合、私のコンテキスト辞書はsettings.GLOBAL_SETTINGSをオーバーライドするということです。 YMMV。

0
desfido

コンテキストプロセッサでは、次のようなものを使用できます。

import settings

context = {}
for item in dir(settings):
    #use some way to exclude __doc__, __name__, etc..
    if item[0:2] != '__':
        context[item] = getattr(settings, item)
0
andrei1089