2012-11-24 11 views
6

Gibt es eine Möglichkeit, URLs mit optionalen URL-Parametern in Flask zu definieren? Im Wesentlichen tun, was ich möchte ist Regeln zu definieren, die für optional angegebene Sprachen erlauben:Optionale URL-Variablen

/ 
/de -> matches/(but doesn't collide with /profile) 
/profile 
/de/profile 

Ich glaube, ich habe einen Weg gefunden, es zu tun, aber es geht entweder eine Änderung, wie Werkzeug zu machen und Flask bearbeitet die Anfrage (Affe-Patching oder Forking der Framework-Quelle). Dies scheint jedoch eine übermäßig komplexe Art und Weise zu sein, mit diesem Problem umzugehen. Gibt es einen einfacheren Weg, dies zu tun, den ich übersehe?

Edit:

Basierend auf Brians Antwort, hier ist, was ich kam mit:

app.py:

from loc import l10n 

def create_app(config):                             
    app = Flask(__name__)                            
    app.config.from_pyfile(config)                          

    bp = l10n.Blueprint()                            
    bp.add_url_rule('/', 'home', lambda lang_code: lang_code)                   
    bp.add_url_rule('/profile', 'profile', lambda lang_code: 'profile: %s' % 
     lang_code) 
    bp.register_app(app)                             

    return app 

if __name__ == '__main__': 
    create_app('dev.cfg').run() 

loc/l10ln.py

class Blueprint(Blueprint_): 
    def __init__(self): 
     Blueprint_.__init__(self, 'loc', __name__) 

    def register_app(self, app): 
     app.register_blueprint(self, url_defaults={'lang_code': 'en'})                 
     app.register_blueprint(self, url_prefix='/<lang_code>') 

     self.app = app 

(ich habe lang_code aus der Variablenliste zu ziehen noch nicht bekommen, wird aber, dass in Kürze tun)

Jetzt imho das ist nur heiß.

Antwort

7

Blueprints könnten dafür geeignet sein, da sie mehrfach registriert werden können.

from flask import Flask, Blueprint 

app = Flask(__name__) 
bp = Blueprint('main', __name__) 

@bp.route('/') 
def hello(lang): 
    return 'Hello ' + lang + '!' 

app.register_blueprint(bp, url_defaults={'lang': 'en'}) 
app.register_blueprint(bp, url_prefix='/<lang>') 

if __name__ == '__main__': 
    app.run() 

Wenn das funktioniert, sieht Internationalized Blueprint URLs in der Flask Dokumentation für eine Art und Weise ein lang Argument in jeder View-Funktion zu vermeiden angeben.

+0

Definitiv der Weg zu gehen, imho, angesichts der (relativen) neuen Schärfe von Blaupausen –

10

Nur für den Fall, dass Sie es nicht wussten, können Sie mehrere Routen für eine Ansicht registrieren. Könnte ein Schmerz es für jede Ansicht zu tun, aber es ist machbar ...

DEFAULT_LANG = 'en' 

@app.route('/profile') 
@app.route('/<lang>/profile') 
def profile(lang=DEFAULT_LANG): 
    pass 

Oder vielleicht könnten Sie Ihre eigene route Dekorateur implementieren, die sowohl automatisch app.route für Szenarien ruft ...

from flask import Flask 

app = Flask(__name__) 

DEFAULT_LANG = 'en' 

def lang_route(rule, **options): 
    def decorator(f): 
     endpoint = options.pop('endpoint', None) 
     app.add_url_rule(rule, endpoint, f, **options) 
     app.add_url_rule('/<lang>%s' % rule, endpoint, f, **options) 
     return f 
    return decorator 

@lang_route('/profile') # also accepts '/<lang>/profile' automatically 
def profile(lang=DEFAULT_LANG): 
    return lang 

if __name__ == '__main__': 
    app.run(debug=True) 
+0

Ich denke, das ist eine großartige und äußerst gründliche Antwort. – jdotjdot

+0

100% der richtige Weg es zu tun. – sberry

+1

Das ist keine schlechte Lösung, aber ich denke, dass Blueprints korrekter sind, da sie entworfen wurden, um eine Reihe von Routen zu kapseln, und Sie einfach alle diese Routen auf einmal manipulieren können. Die [Flask-Dokumente empfehlen] (http://flask.pooco.org/docs/patterns/urlprocessors/#internationalized-application-urls) unter Verwendung von Blaupausen für die URL-Internationalisierung: "Sie können dies weiter verbessern, indem Sie Ihren eigenen Dekorator schreiben, der URLs voranstellt mit dem Sprachcode, aber die schönere Lösung ist ein Blueprint. " –