Uso de procesadores de URL

Changelog

Nuevo en la versión 0.7.

Flask 0.7 introduce el concepto de procesadores de URL. La idea es que puedes tener un montón de recursos con partes comunes en la URL que no siempre quieres proporcionar explícitamente. Por ejemplo, puedes tener un montón de URLs que tienen el código del lenguaje en él, pero no quieres tener que manejarlo tú mismo en cada función.

Los procesadores de URL son especialmente útiles cuando se combinan con blueprints. Aquí trataremos tanto los procesadores de URL específicos de la aplicación como los específicos de los planos.

URLs de aplicaciones internacionalizadas

Considere una aplicación como esta:

from flask import Flask, g

app = Flask(__name__)

@app.route('/<lang_code>/')
def index(lang_code):
    g.lang_code = lang_code
    ...

@app.route('/<lang_code>/about')
def about(lang_code):
    g.lang_code = lang_code
    ...

Esto es un montón de repeticiones, ya que tienes que manejar la configuración del código de idioma en el objeto g tú mismo en cada función. Por supuesto, se podría utilizar un decorador para simplificar esto, pero si quieres generar URLs de una función a otra tendrías que seguir proporcionando el código de idioma explícitamente, lo que puede ser molesto.

Para esto último, es donde entran las funciones url_defaults(). Pueden inyectar automáticamente valores en una llamada a url_for(). El código siguiente comprueba si el código de idioma no está todavía en el diccionario de valores de URL y si el endpoint quiere un valor llamado 'lang_code:

@app.url_defaults
def add_language_code(endpoint, values):
    if 'lang_code' in values or not g.lang_code:
        return
    if app.url_map.is_endpoint_expecting(endpoint, 'lang_code'):
        values['lang_code'] = g.lang_code

El método is_endpoint_expecting() del mapa URL puede utilizarse para averiguar si tiene sentido proporcionar un código de idioma para el punto final dado.

El reverso de esa función son los url_value_preprocessor(). Se ejecutan justo después de que la solicitud haya sido emparejada y pueden ejecutar código basado en los valores de la URL. La idea es que saquen información del diccionario de valores y la pongan en otro lugar:

@app.url_value_preprocessor
def pull_lang_code(endpoint, values):
    g.lang_code = values.pop('lang_code', None)

De esta manera ya no tienes que hacer la asignación de lang_code a g en cada función. Puedes mejorar esto escribiendo tu propio decorador que anteponga a las URLs el código de idioma, pero la solución más bonita es usar un blueprint. Una vez que el 'lang_code' es sacado del diccionario de valores y ya no será reenviado a la función de la vista reduciendo el código a esto:

from flask import Flask, g

app = Flask(__name__)

@app.url_defaults
def add_language_code(endpoint, values):
    if 'lang_code' in values or not g.lang_code:
        return
    if app.url_map.is_endpoint_expecting(endpoint, 'lang_code'):
        values['lang_code'] = g.lang_code

@app.url_value_preprocessor
def pull_lang_code(endpoint, values):
    g.lang_code = values.pop('lang_code', None)

@app.route('/<lang_code>/')
def index():
    ...

@app.route('/<lang_code>/about')
def about():
    ...

URLs de Blueprint internacionalizadas

Debido a que los blueprints pueden anteponer automáticamente todas las URLs con una cadena común, es fácil hacerlo automáticamente para cada función. Además, los blueprints pueden tener procesadores de URL por blueprint, lo que elimina un montón de lógica de la función url_defaults() porque ya no tiene que comprobar si la URL está realmente interesada en un parámetro 'lang_code':

from flask import Blueprint, g

bp = Blueprint('frontend', __name__, url_prefix='/<lang_code>')

@bp.url_defaults
def add_language_code(endpoint, values):
    values.setdefault('lang_code', g.lang_code)

@bp.url_value_preprocessor
def pull_lang_code(endpoint, values):
    g.lang_code = values.pop('lang_code')

@bp.route('/')
def index():
    ...

@bp.route('/about')
def about():
    ...