套在瓶子里的蓝图?

2024-05-13 01:49:59 发布

您现在位置:Python中文网/ 问答频道 /正文

我对Flask还不熟悉,所以可能有一个很明显的方法来实现这一点,但是我还没有从文档中找到答案。我的应用程序分为几个几乎完全不同的部分,它们共享用户/会话/安全性和基本模板等内容,但大多数情况下不会进行太多交互,应该在不同的路径(如/part1/...)下路由。我想这正是蓝图的目的。但如果我需要在蓝图下进一步分组路由和逻辑呢?

例如,我用blueprint1url_prefix='/blueprint1'创建了一个视图集合,在这个集合中,我希望有一个围绕用户共享照片和其他用户评论照片的视图。我想不出比这更好的办法了:

# 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():
    ...

这里的问题是,与blueprint1的照片部分相关的所有视图都位于“顶层”,可能带有视频或音频或其他内容(命名为videos_index()…)的蓝图。是否有任何方法可以以更层次化的方式对它们进行分组,比如模板如何在'blueprint1/photos'子目录下进行分组?当然,我可以将所有照片视图放在它们自己的模块中,以保持它们的独立组织,但是如果我想将父视图'blueprint1/photos'路径更改为其他路径呢?我确信我可以发明一个函数或装饰器,在同一根路径下对相关的路由进行分组,但是我仍然必须用photos_前缀命名所有函数,并像url_for('blueprint1.photos_show')一样引用它们。当一个Flask应用程序变大时,蓝图似乎就是答案,而您需要将相似的部分分组和分隔在一起,但当蓝图本身变大时,你不能做同样的事情。

作为参考,在Laravel中,可以在视图是方法的Controller类下对相关“视图”进行分组。控制器可以驻留在分层名称空间中,如app\Http\Controllers\Blueprint1\Photocontroller,路由可以分组在一起,如

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

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

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

    });

});

路径可以像action('Blueprint1\PhotoController@index')那样得到。

如果我能做一个照片蓝图,然后做blueprint1.register_blueprint(photos_blueprint, url_prefix='/photos')或类似的事情,这些问题几乎可以解决。不幸的是,烧瓶似乎不支持这样的嵌套蓝图。有没有别的方法来处理这个问题?


Tags: 方法用户路径视图id路由getprefix
3条回答

这是我的解决方法:

导入蓝图时,我定义嵌套的路由:

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>')

在设计图中,我重用了路由解析函数。例如,在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

category_endpoints文件中:

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

等等。。。使用这种方法,我的蓝图也可以用于直接路由,如/products/<int:product_id>

这种方法对我很有效。我希望它也能帮助你。

不幸的是,嵌套的蓝图不是Flask中的当前特性。你得手动操作。你也许可以为你的具体情况编写一些代码,但一般的解决方案还没有添加到烧瓶。关于问题跟踪者的一些讨论:


将可嵌套的蓝图添加到烧瓶中并不像自动向路由添加前缀那样简单。在嵌套时,需要考虑蓝图的许多其他特性,这些特性使得一般的实现更加复杂。这还没有实现的原因是,社区中没有人对它有足够的需求,这不是通过快速的解决方案和提供一般实现来解决的。

我创建了一个名为NestedBlueprint的类来破解它。

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)

这是我的基本文件,其中包含蓝图:panel/__init__.py

from flask import Blueprint

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

from . import customize

这是包含嵌套蓝图的特定/嵌套文件: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 ':)'

你可以这样打电话:

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

相关问题 更多 >