2

Flaskで a を使用してかなり奇妙な問題が発生していますjinja2.ChoiceLoader(また、複数のパスを使用して試しましたがFileSystemLoader、喜びはありません)。

そのように、いくつかの「テーマ」ディレクトリがあります。

/templates/
  themes/
    default/
      layout.html
      menu.html
    blue/
      layout.html
    grey/
      menu.html
    ...

default/そして、選択したテーマに必要なテンプレートがない場合にフォールバックしたいので、ChoiceLoader を使用しました。

@app.before_request
def setup_request():
    current_theme = get_theme()
    logging.info('Using theme %s'%(current_theme))
    app.jinja_loader = jinja2.ChoiceLoader([
        jinja2.FileSystemLoader('/templates/themes/%s/'%(current_theme)),
        jinja2.FileSystemLoader('/templates/themes/default/')
    ])

それは素晴らしいことですが、変更し<current_theme>ても、Apache をリロードするか、Flask 開発サーバーを再起動するまで、古いフォルダーからテーマが読み込まれます。

新しいテーマを使用する必要があります。ロギングは、変更されたテーマを使用していると言っていますが、明らかにapp.jinja_loaderハニーアナグマに少し似ています...Apacheをリロードするまで完全に無視しています。

編集:これは、同じ名前のすべてのファイルが同じファイルであると考えるFlaskに関連しているようです。組み込みサーバー (DEBUG=True)、Cherry、mod_wsgi で再現できます。この人も同様の問題を抱えているようですが、単純な解決策はありません:フラスコ ブループリント テンプレート フォルダー1 つのアプリにテンプレートをカスケードする必要があるという意味で、私の状況は異なります。彼の問題はブループリント間のテンプレートのカスケードに関連していますが、内部では同じ問題である可能性があります。

「get_theme()」呼び出しのコードは次のとおりです。

def get_theme():
    # I know this is unsafe, testing only
    return request.args.get('theme','default')

編集 2: CSS だけでなく、テーマ間で HTML と JavaScript を変更する必要があります。これが、さまざまな CSS ファイルをロードするだけではない理由です。また、これらのテーマの一部はモバイル デバイス用であり、他のテーマとの共通点はほとんどありません。

編集 3: 2 つのソリューション。解決策 1 : 「blue.layout.html」や「default.layout.html」のように、ファイルに一意の名前を付けます。これは完全に機能しますが、必要に応じてカスケードしません。解決策 2 : 相対パスを使用するため、代わりにinclude 'file.html'を使用しますinclude 'theme/blue/file.htmlget_theme_file()アクティブなテーマをチェックし、ファイルが存在するかどうかをチェックし (存在しない場合は「デフォルト」テーマにフォールバック)、相対パスを返す関数を作成することで、カスケードを実現しました。含めるすべてが のように見えることを確認する必要があります{% include get_theme_file('file.html') %}これはエレガントではありませんが、ここで使用された Flask を使用した低レベルの操作よりもエレガントであることがわかりました。

4

2 に答える 2

0

ちなみに、複数の場所をFileSystemLoaderに渡すことができます。これは、テンプレートをロードするための推奨される方法です。

これは、Apache で予期される動作mod_wsgiです (使用していると思います)。ファイル システムの変更によって、すべてのプロセスのリロードがトリガーされるわけではありません。これについて説明し、追加する回避策を提供する Flask docs のこのエントリを参照してください。

WSGIScriptReloading On

アプリケーションの構成セクションに移動しtouch、ファイルを ing しwsgiて子プロセスのリロードをトリガーします。

これが意図したものであると確信していますか? ほとんどのテーマ切り替えトリックは、カスケーディング スタイル シート (CSS)のカスケード部分に依存してテーマを制御します。

于 2013-04-14T04:41:00.340 に答える
0

さて、この問題に遭遇したのは私だけではありません。問題は、Flask がファイル名に基づいてキャッシュすることです。相対パスを含めない場合は、最初に読み込まれたものだけをキャッシュします。動的なカスケード テンプレートを実現するには、3 つの方法があります。

  1. Jinja builtins をオーバーライドします。これは非常に紛らわしいことがわかりました。私はこの解決策について十分に頭が良くありません。
  2. ファイルごとに異なる WSGI プロセスを提供します。ここでの設定は、動的なサイトには少し多すぎるようです。Flask は WSGI プロセスごとにファイル名をキャッシュするため、たとえば、複数の Cherry WSGI サーバーで何かを行うことができます。
  3. ロード パスにテーマを含めます。関数を作成して でロードし、context_processorその関数を使用してテンプレート ファイルのみをロードします。この関数は、デフォルト以外のテーマをチェックし、ファイルが存在するかどうかをチェックして、それを返す必要があります。したがって、テンプレート呼び出しはget_theme_file('layout.html')、相対パスを返す (のようにthemes/blue/layout.html) になります。

オプション 3 の例。

def get_theme_file(fname):
    theme = get_theme()
    if os.path.exists(os.path.join(theme.theme_dir, fname)):
        return os.path.join('themes', theme.name, fname)
    return os.path.join('themes', 'default', fname)
...
    # Each render_template should reference this
    return render_template(get_theme_file('layout.html'))

テンプレートにテーマ ファイルを含める場合:

{% include get_theme_file('layout.html') %}

残念ながら、これはキャッシュされませんが、最適化する方法がいくつかあります。おそらく の をキャッシュし、os.listdir呼び出しごとget_theme().theme_dirにファイルシステムを読み取る代わりに、キャッシュされたリストに対してチェックを行うだけです。get_theme_fileinlistdir

これは Flask 固有のものであることに注意してください。プレーンな Jinja2 と自分の WSGI サーバーでは、この動作を再現できませんでした。Flask はこの特定のプロジェクトには不適切な選択だったと言う人もいるかもしれませんが、Flask が行う他のすべてのことによる節約はそれだけの価値があると私は主張します。

于 2013-04-14T10:17:55.147 に答える