2013-06-16 14 views
7

は、私は次のように、3つの可変要素とURLルールを定義したい:URLルーティングの競合が

@app.route('/<var_1>/<var_2>/<var3>/') 

しかし、私は開発サーバーが静的で一致しようとする前に、このようなルールを評価することを見つけますファイル。したがって、次のようなものがあります。

/static/images/img.jpg 

は、組み込みの静的ファイルハンドラに転送されるのではなく、私のURLルールによって捕捉されます。開発サーバーに最初に静的ファイルを一致させる方法はありますか?

P.S.これは、ルールに2つ以上の変数コンポーネントがある場合にのみ問題になります。

+0

面白いのカップルが読み込み:[フラスコルーティングシステム](http://flask.pocoo.org/docs/design/#the-routing-system)と[WERKZEUGルーティング](のhttp:// WERKZEUG .pocoo.org/docs/routing /#module-werkzeug.routing)。 [Blueprints](http://flask.pocoo.org/docs/blueprints/)を使って探検してみることもできます。 –

答えて

16

これはWERKZEUGルート最適化機能です。 Map.addMap.updateRule.match_compare_keyを参照してください。

def match_compare_key(self): 
    """The match compare key for sorting. 

    Current implementation: 

    1. rules without any arguments come first for performance 
    reasons only as we expect them to match faster and some 
    common ones usually don't have any arguments (index pages etc.) 
    2. The more complex rules come first so the second argument is the 
    negative length of the number of weights. 
    3. lastly we order by the actual weights. 

    :internal: 
    """ 
    return bool(self.arguments), -len(self._weights), self._weights 

self.argumentsがあります - 現在の引数、self._weights - パスの深さ。我々は(True, -3, [(1, 100), (1, 100), (1, 100)])を持って'/<var_1>/<var_2>/<var3>/'するため

(1, 100) - デフォルトの文字列引数で、最大長100です。

'/static/<path:filename>'の場合は(True, -2, [(0, -6), (1, 200)])です。パス以外の引数文字列の長さstatic(1, 200) - - パス文字列引数の最大長200

だから私はマップルールのFlask.url_mapのための独自のMap実装や設定の優先順位を設定するための任意の美しい道を見つけることができません(0, 1)があります。ソリューション:

  1. app = Flask(static_path='static', static_url_path='/more/then/your/max/variables/path/depth/static')としてFlaskアプリケーションを設定します。
  2. 変更@app.route('/prefix/<var_1>/<var_2>/<var3>/')から@app.route('/<var_1>/<var_2>/<var3>/')
  3. @app.route('/<no_static:var_1>/<var_2>/<var3>/')として独自のコンバータを追加してください。
  4. インポートwerkzeug.routingは、インプリメンテーション、輸入flaskを所有するwerkzeug.routing.Mapを変更する、独自のマップの実装を作成します。
  5. サーバーを本番環境で使用します。
+0

まずはあなたの答えが間違っていると思います。 オプション1では、静的ファイルが提供されるURLを変更し、そのURLに十分な「ダミー」サブディレクトリを追加して、可変コンポーネントから構成されている既存のURLルールと衝突する可能性がなくなります。 私の例では、 'static_url_path'は'/static/static/static/static'のように変更する必要があり、 '@ app.route( '/ ///') ' –

+0

私はオプション1を使用しました。私は理由はわかりませんが、static_path引数を持っていても機能しませんでしたが、削除したときに機能しました。 'app = Flask(__ name__、static_url_path = '/ r/s/static')' – trevor

6

このように、この動作はWerkzeugの中で深く設定されており、実際にはFlaskからそれを処理するためのエレガントな方法はありません。私が思い付くことができる最高の回避策は次のとおりです。

は次のように補完的な静的ファイルハンドラを定義します。ここでは

@app.route('/static/<subdir>/<path:filename>/') 
def static_subdir(subdir=None, filename=None): 

    directory = app.config['STATIC_FOLDER'] + subdir 
    return send_from_directory(directory, filename) 

は、app.config['STATIC_FOLDER']は、アプリケーションを実行するマシン上の静的フォルダへのフルパスです。

さて、このハンドラだけでは3つの可変要素との私の見解を残し、/static/images/img.jpgのようなものをキャッチします。この一周する

+0

'Flask'アプリケーションの設定でこれを行うことができるので、独自のハンドラを追加する必要はありません。私の答えの解決策1を参照してください: 'Flaskのアプリケーションを設定する= Flask(static_path = 'static'、static_url_path = '/ more/then/your/max/variables/path/depth/static')' ( 'static'、filename = 'images/img.jpg'の場合は問題ありません。) – tbicr

+0

あなたの解決策はここで最もよく言及されていますが、petrus。ダミーサブディレクトリを導入することは、URLルールで明示的にキャッチするよりも醜いです。 –

3

一つの方法は、登録されたルールのmatch_compare_key()方法をなりすましによるソートアルゴリズムのルールをカンニングすることです。このハックは、青写真ではなく、app.route()(Flaskオブジェクト)で直接登録されたルートでのみ機能することに注意してください。 Blueprintsのルートは、主なアプリケーションでの青写真の登録時にのみグローバルURLマップに追加され、生成されたルールを変更するのは難しい作業です。

# an ordinary route 
@app.route('/<var1>/<var2>/<var3>') 
def some_view(var1, var2, var3): 
    pass 

# let's find the rule that was just generated 
rule = app.url_map._rules[-1] 

# we create some comparison keys: 
# increase probability that the rule will be near or at the top 
top_compare_key = False, -100, [(-2, 0)] 
# increase probability that the rule will be near or at the bottom 
bottom_compare_key = True, 100, [(2, 0)] 

# rig rule.match_compare_key() to return the spoofed compare_key 
rule.match_compare_key = lambda: top_compare_key 

この場合、結果のスプーフィングされた関数はルールオブジェクトにバインドされていないことに注意してください。したがって、rule.match_compare_key()を呼び出すと、関数はself引数を受け取りません。あなたが適切に機能をバインドしたい場合は、代わりに次の操作を行います。

spoof = lambda self: top_compare_key 
rule.match_compare_key = spoof.__get__(rule, type(rule)) 

を我々はデコレータ

def weighted_route(*args, **kwargs): 
    def decorator(view_func): 
     compare_key = kwargs.pop('compare_key', None) 
     # register view_func with route 
     app.route(*args, **kwargs)(view_func) 

     if compare_key is not None: 
      rule = app.url_map._rules[-1] 
      rule.match_compare_key = lambda: compare_key 

     return view_func 
    return decorator 

# can be used like @app.route(). To weight the rule, just provide 
# the `compare_key` param. 
@weighted_route('/<var1>/<var2>/<var3>', compare_key=bottom_compare_key) 
def some_view(var1, var2, var3): 
    pass 

コンテキストマネージャとして実装同じハックで上記を一般化することができます。

import contextlib 

@contextlib.contextmanager 
def weighted_route(compare_key=None): 
    yield 
    if compare_key is not None: 
     rule = app.url_map._rules[-1] 
     rule.match_compare_key = lambda: compare_key 

# and to use 

with weighted_route(compare_key): 
    @app.route('/<var1>/<var2>/<var3>') 
    def some_view(var1, var2, var3): 
     pass