如何使用Flask创建基于模板的动态URL



我有一个烧瓶路线,如下所示:

@app.route('/product/<string:slug>')
def product(slug):
# some codes...
return render_template('product.html', product=product)

不同的客户使用该项目(不同的网站,相同的基础设施(。每个客户都希望产品URL有所不同。喜欢

asite.com/product-nike-shoe-323

bsite.com/nike-shoe

csite.com/product/nike-shoue

与。与

如何将URL结构设置为来自数据库?

类似:

url_config = "product-{product_name}-{product_id}"

url_config = "product-{product_id}"

注意:请不要重定向。

当你在这里说"数据库"时,我不是100%清楚你指的是什么。根据上下文,我推断您可能在谈论Flask Config对象。如果是这种情况,您只需在设置应用程序配置后立即注册查看功能即可。只需调用app.add_url_rule()即可从配置中注册URL模式,指向您选择的视图函数。

然而,如果你谈论的是SQL或NoSQL数据库,并且你已经构建了一个用于注册路由的web UI,那么就不要发布。Flask路由可以在任何时候向应用程序对象注册。在Flask应用程序的生命周期中,没有一点是你不能再注册路线的!

注册路由所做的就是在URL模板和端点名称(一个不透明的字符串(之间创建映射。大多数时候,您还注册了一个要调用的函数来处理特定的端点,大多数时候,Flask从该函数推断端点名称。一旦在映射中注册,任何下一个传入请求都可以路由到给定端点的函数。

因此,Flask保留了两张地图:

  • 从url路由->端点名称:Flask.url_map
  • 从端点名称->函数:Flask.view_functions

也就是说,有API用于删除更改url注册(当然,除了重新启动服务器(。您不能更改url路由、给定路由的端点名称或哪个端点映射到哪个函数。该框架的意图是在首次启动服务器时尽早注册路由,通过导入或绑定到应用程序时直接运行的代码(Blueprint和Flask扩展完成后者(。大多数Flask应用程序都会创建他们的Flask实例,注册所有路由和扩展,然后将该实例传递给WSGI服务器进行请求调度,仅此而已。但在此之后,实现中没有任何内容可以阻止您注册更多路由。

如果你想从数据库信息中注册URL路由,你必须至少注意以下两件事:

  1. 在启动时注册现有路由。一旦建立了与数据库的连接,就可以检索现有路线并进行注册
  2. 如果数据库中添加了一个新条目,请注册一个新路由

首先:如果我要实现这样的东西,我会使用一个视图函数。您总是可以通过分别查看request.url_rulerequest.endpoint来找出匹配的url规则以及映射到的端点名称。

接下来,我将从数据库中为每个url规则显式生成端点名称。使用名称中的主键;您希望能够从端点名称中查找数据库行,反之亦然。如何做到这一点取决于你自己;让我们假设您知道如何做到这一点,并且您有两个名为pk_from_endpoint()endpoint_from_pk()的函数。

您的查看功能可以如下所示:

from flask import request
def product_request(**kwargs):
key = pk_from_endpoint(request.endpoint)
row = database_query(key)
# … process request

您使用为给定数据库行注册路由

app.add_url_route(row.url_config, endpoint_from_pk(row.id), product_request)

如前所述,您不能更改URL注册。但是,只要很少更改这些URL,您就可以添加新的注册,并且对于任何旧条目,使用abort(404)返回404 Not Found响应。

这在Flask的路由系统中是不可能的。URL映射应该在启动时定义,之后不会更改。

但是,如果您有一些特定的路径需要动态部件(例如/product/WHATEVER(,那么您可以为/product/<slug>注册一个路由,并在视图函数中查询数据库。


也就是说,如果你真的想在数据库中使用URL规则,并且不介意在启动期间连接到数据库(通常这很难看(,那么没有什么可以阻止你在启动时查询数据库,并根据数据库中的数据定义URL规则。很难看,但可行。

示例:

with app.app_context():
url_map = {u.endpoint: u.rule for u in URLRules.query}
@app.route(url_map['foo'])
def foo():
...

当然,这样做会让你的应用程序更难很好地构建,除非你在一个地方为所有端点使用app.add_url_rule(),而不是@app.route()装饰器。

当然,蓝图也是如此。

最新更新