2015-10-07 3 views
7

Sono ancora nuovo in Flask, quindi potrebbe esserci un modo ovvio per farlo, ma non sono stato in grado di capirlo così lontano dalla documentazione. La mia app è divisa in diverse parti per lo più disparate che condividono cose come utenti/sessioni/sicurezza e modello base e tutto, ma per lo più non interagiscono molto, e dovrebbero essere instradati in percorsi diversi come /part1/.... Penso che questo sia esattamente ciò che i progetti sono per. Ma cosa succede se ho bisogno di raggruppare percorsi e logica ulteriormente sotto un progetto?Cianografie annidate in una fiaschetta?

Ad esempio, ho blueprint1 con url_prefix='/blueprint1' e forse con questo voglio avere una raccolta di viste che ruotano attorno a un utente che condivide foto e altri utenti che commentano su di loro. Non riesco a pensare ad un modo migliore di farlo che:

# app/blueprints/blueprint1/__init__.py 

blueprint1 = Blueprint('blueprint1', __name__, template_folder='blueprint1') 

@blueprint1.route('/photos') 
def photos_index(): 
    return render_template('photos/index.html') 

@blueprint.route('/photos/<int:photo_id>') 
def photos_show(photo_id): 
    photo = get_a_photo_object(photo_id) 
    return render_template('photos/show.html', photo=photo) 

@blueprint.route('/photos', methods=['POST']) 
def photos_post(): 
    ... 

Il problema qui è che tutti i punti di vista relativi alla sezione foto di blueprint1 si trovano presso il "livello superiore", a destra con forse modelli per video o audio o qualsiasi altra cosa (denominata videos_index() ...). C'è un modo per raggrupparli in un modo più gerarchico, come il modo in cui i modelli vanno sotto la sottodirectory 'blueprint1/photos'? Naturalmente posso mettere tutte le viste delle foto nel proprio modulo per tenerle organizzate separatamente, ma cosa succede se voglio cambiare il percorso genitore 'blueprint1/photos' a qualcos'altro? Sono sicuro di poter inventare una funzione o un decoratore che raggruppa percorsi correlati sotto lo stesso percorso radice, ma poi devo ancora nominare tutte le funzioni con il prefisso photos_ e farle riferimento come url_for('blueprint1.photos_show') Sembra che i progetti siano la risposta quando un pallone l'app diventa grande e devi raggruppare e compartimentare parti simili insieme, ma non puoi fare la stessa cosa quando i progetti stessi diventano grandi.

Per riferimento, in Laravel è possibile raggruppare "viste" correlate in una classe Controller in cui le viste sono metodi. Controllori possono risiedere in domini gerarchici come app\Http\Controllers\Blueprint1\Photocontroller, percorsi possono essere raggruppati come

Route::group(['prefix' => 'blueprint1'], function() { 

    Route::group(['prefix' => 'photos'], function() { 

     Route::get('/', ['as' => 'blueprint.photos.index', 'uses' => '[email protected]']); 
     Route::post('/', ['as' => 'blueprint.photos.store', 'uses' => '[email protected]']); 
     Route::get('/{id}', ['as' => 'blueprint.photos.get', 'uses' => '[email protected]']) 
      ->where('id', '[0-9]+'); 

    }); 

}); 

e percorsi possono essere ottenuti come action('Blueprint1\[email protected]').

Se solo potessi fare un progetto fotografico, quindi basta fare blueprint1.register_blueprint(photos_blueprint, url_prefix='/photos') o simili, questi problemi sarebbero praticamente risolti. Purtroppo Flask non sembra supportare i progetti di nesting come questo. C'è un modo alternativo per gestire questo problema?

risposta

4

Ho fatto una classe chiamata NestedBlueprint a sfruttarla.

class NestedBlueprint(object): 
    def __init__(self, blueprint, prefix): 
     super(NestedBlueprint, self).__init__() 
     self.blueprint = blueprint 
     self.prefix = '/' + prefix 

    def route(self, rule, **options): 
     rule = self.prefix + rule 
     return self.blueprint.route(rule, **options) 

Ecco il mio file di base che contiene il progetto: panel/__init__.py

from flask import Blueprint 

panel_blueprint = Blueprint(PREFIX, __name__, url_prefix='/panel') 

from . import customize 

Ecco il file specifico/nidificato che contiene modello nidificato: panel/customize.py

from rest.api.panel import panel_blueprint 
from rest.api.util.nested_blueprint import NestedBlueprint 

nested_blueprint = NestedBlueprint(panel_blueprint, 'customize') 


@nested_blueprint.route('/test', methods=['GET']) 
def test(): 
    return ':)' 

È quindi possibile chiamare come this:

$ curl http://localhost:5000/panel/customize/test 
:) 
+0

questo metodo non funziona con @ blueprint_name.before_request –

0

Qui è la mia soluzione:

Durante l'importazione di un progetto, mi definisco miei percorsi nidificati:

app.register_blueprint(product_endpoints, url_prefix='/sites/<int:site_id>/menus/<int:menu_id>/categories/<int:category_id>/products/<int:product_id>') 
app.register_blueprint(category_endpoints, url_prefix='/sites/<int:site_id>/menus/<int:menu_id>/categories/<int:category_id>') 
app.register_blueprint(menu_endpoints, url_prefix='/sites/<int:site_id>/menus/<int:menu_id>') 
app.register_blueprint(site_endpoints, url_prefix='/sites/<int:site_id>') 

E dentro i progetti, che sto riutilizzo funzioni percorso di analisi. Ad esempio, nel file product_endpoints:

from category_endpoints import get_category_data 

product_endpoints = Blueprint('product_endpoints', __name__) 

@product_endpoints.url_value_preprocessor 
def get_product_data(endpoint, values): 
    if 'category_id' in values: 
     get_category_data(endpoint, values) 

    product = Product.get_by_id(int(values.pop('product_id'))) 

    if not product: 
     abort(404) 

    g.product = product 

e in category_endpoints di file:

from menu_endpoints import get_menu_data 

category_endpoints = Blueprint('category_endpoints', __name__) 

@category_endpoints.url_value_preprocessor 
def get_category_data(endpoint, values): 
    if 'menu_id' in values: 
     get_menu_data(endpoint, values) 
    category = ProductCategory.get_by_id(int(values.pop('category_id'))) 

    if not category: 
     abort(404) 

    g.category = category 

ecc ... Con questo approccio, il mio modello è utilizzabile anche con percorsi diretti come /products/<int:product_id>.

Questo approccio ha funzionato molto bene per me. Spero possa aiutarti anche tu.