Flask 重定向数据
Flask redirect with data
我有一个带有 GET 处理程序的 Flask 应用程序,该处理程序将配方 ID 作为 URL 参数,它从数据库中检索配方,然后呈现它:
@app.route('/recipe/<int:id>', methods=['GET'])
def get(id):
recipe = get_recipe_from_db(id)
return render_template('recipe.html', recipe=recipe)
这会导致 URL 类似于 /recipe/5
。我希望食谱标题成为结果 URL 的一部分,而不是仅在 URL 中显示 id,例如 recipe/5/lemon-cake
。在第一个请求中,只有 id 是已知的。
我不确定这样做的好方法是什么。到目前为止,我已经想出了以下内容:
@app.route('/recipe/<int:id>', methods=['GET'])
def get(id):
recipe = get_recipe_from_db(id)
return redirect(url_for('get_with_title', id=id, title=urlify(recipe.title)))
@app.route('/recipe/<int:id>/<title>', methods=['GET'])
def get_with_title(id, title=None):
recipe = get_recipe_from_db(id)
return render_template('recipe.html', recipe=recipe)
这是有效的(即当用户访问 /recipe/5
时它重定向到 /recipe/5/lemon-cake
)但是从数据库中检索相同的配方两次。
有没有更好的方法来解决这个问题?
注意:recipe
object 很大,包含多个字段,我不想不必要地通过网络传递它。
只需将加载的配方作为参数传递:
@app.route('/recipe/<int:id>', methods=['GET'])
def get(id):
recipe = get_recipe_from_db(id)
return redirect(
url_for(
'get_with_title',
id=id,
title=urlify(recipe.title),
recipe=recipe,
))
@app.route('/recipe/<int:id>/<title>', methods=['GET'])
def get_with_title(id, title=None, recipe=None):
if recipe is None:
recipe = get_recipe_from_db(id)
return render_template('recipe.html', recipe=recipe)
您只能研究 将 URL 更改为 javascript,如图 here。这样,您就不会进行任何重定向或重新加载。
如果你不想惹javascript,让我们想想后端解决方案:
从数据库加载两次显着的性能开销值得一个复杂的解决方案吗?如果没有,你的解决方案很好。
如果你真的想避免加载整个 recipe
,你可以在你的 get
方法中只加载标题,而不是整个 object.
您可以编写自定义 get_recipe_title(id)
,它(大致) SELECT title FROM recipes WHERE id={id}
.
如果使用 SQLAlchemy,您可能会使用 load_only
- here
如果您希望 'recipe title' 出现在 URL 中,您的解决方案不适合。您应该在 'request' 之前执行此操作。可能有一个 HTML 页面,您可以在其中提交食谱数据以列出所有食谱。
在您的 HTML 页面中尝试以下操作:
<ul>
{% for recipe in recipes %}
<li><a href="/postdetail/{{recipe.id}}/{{recipe.title}}"></li>
{% endfor %}
</ul>
之后,当您单击该食谱时,您还可以看到标题。
选项 1
最简单的解决方案是在收到响应后立即在客户端修改 URL;因此,不需要重定向 and/or 查询数据库两次。这可以通过使用 history.pushState()
or history.replaceState()
.
来实现
客户端
<!DOCTYPE html>
<html>
<head>
<script>
function modify_url() {
var title = {{recipe.title|tojson}};
var id = {{recipe.id|tojson}};
window.history.pushState('', '', id + "/" + title);
}
</script>
</head>
<h2>Recipe for {{recipe.title}}</h2>
<body onload="modify_url()"></body>
</html>
服务器端
@app.route('/recipe/<int:id>', methods=['GET'])
def get(id):
recipe = get_recipe_from_db(id)
return render_template('recipe.html', recipe=recipe)
您可能还想保留 get_with_title()
路由,以防用户 bookmark/share URL(包括标题)并希望它可以访问(否则,访问时会返回“Not Found”错误。
选项 2
如果您不希望每次收到新请求时都查询数据库——甚至不希望检索菜谱条目的 title
(不是每一列)——并且您有足够的内存来保存数据,我建议在启动时查询一次数据库(只选择id
和title
)并创建一个字典,这样你就可以快速查找一个title
来自食谱 id
。请注意,以这种方式,每次对 table 执行 INSERT/DELETE/etc 操作时,必须相应地更新该字典。因此,如果您经常在 table 上进行此类操作,可能不是解决问题的最佳方法,最好继续查询 table 只是为了检索 title
.
recipes = dict((row[0], row[1]) for row in result) # where row[0] is id and row[1] is title
然后在您的端点:
@app.route('/recipe/<int:id>', methods=['GET'])
def get(id):
title = recipes.get(id)
return redirect(url_for('get_with_title', id=id, title=urlify(title)))
我有一个带有 GET 处理程序的 Flask 应用程序,该处理程序将配方 ID 作为 URL 参数,它从数据库中检索配方,然后呈现它:
@app.route('/recipe/<int:id>', methods=['GET'])
def get(id):
recipe = get_recipe_from_db(id)
return render_template('recipe.html', recipe=recipe)
这会导致 URL 类似于 /recipe/5
。我希望食谱标题成为结果 URL 的一部分,而不是仅在 URL 中显示 id,例如 recipe/5/lemon-cake
。在第一个请求中,只有 id 是已知的。
我不确定这样做的好方法是什么。到目前为止,我已经想出了以下内容:
@app.route('/recipe/<int:id>', methods=['GET'])
def get(id):
recipe = get_recipe_from_db(id)
return redirect(url_for('get_with_title', id=id, title=urlify(recipe.title)))
@app.route('/recipe/<int:id>/<title>', methods=['GET'])
def get_with_title(id, title=None):
recipe = get_recipe_from_db(id)
return render_template('recipe.html', recipe=recipe)
这是有效的(即当用户访问 /recipe/5
时它重定向到 /recipe/5/lemon-cake
)但是从数据库中检索相同的配方两次。
有没有更好的方法来解决这个问题?
注意:recipe
object 很大,包含多个字段,我不想不必要地通过网络传递它。
只需将加载的配方作为参数传递:
@app.route('/recipe/<int:id>', methods=['GET'])
def get(id):
recipe = get_recipe_from_db(id)
return redirect(
url_for(
'get_with_title',
id=id,
title=urlify(recipe.title),
recipe=recipe,
))
@app.route('/recipe/<int:id>/<title>', methods=['GET'])
def get_with_title(id, title=None, recipe=None):
if recipe is None:
recipe = get_recipe_from_db(id)
return render_template('recipe.html', recipe=recipe)
您只能研究 将 URL 更改为 javascript,如图 here。这样,您就不会进行任何重定向或重新加载。
如果你不想惹javascript,让我们想想后端解决方案:
从数据库加载两次显着的性能开销值得一个复杂的解决方案吗?如果没有,你的解决方案很好。
如果你真的想避免加载整个 recipe
,你可以在你的 get
方法中只加载标题,而不是整个 object.
您可以编写自定义 get_recipe_title(id)
,它(大致) SELECT title FROM recipes WHERE id={id}
.
如果使用 SQLAlchemy,您可能会使用 load_only
- here
如果您希望 'recipe title' 出现在 URL 中,您的解决方案不适合。您应该在 'request' 之前执行此操作。可能有一个 HTML 页面,您可以在其中提交食谱数据以列出所有食谱。
在您的 HTML 页面中尝试以下操作:
<ul>
{% for recipe in recipes %}
<li><a href="/postdetail/{{recipe.id}}/{{recipe.title}}"></li>
{% endfor %}
</ul>
之后,当您单击该食谱时,您还可以看到标题。
选项 1
最简单的解决方案是在收到响应后立即在客户端修改 URL;因此,不需要重定向 and/or 查询数据库两次。这可以通过使用 history.pushState()
or history.replaceState()
.
客户端
<!DOCTYPE html>
<html>
<head>
<script>
function modify_url() {
var title = {{recipe.title|tojson}};
var id = {{recipe.id|tojson}};
window.history.pushState('', '', id + "/" + title);
}
</script>
</head>
<h2>Recipe for {{recipe.title}}</h2>
<body onload="modify_url()"></body>
</html>
服务器端
@app.route('/recipe/<int:id>', methods=['GET'])
def get(id):
recipe = get_recipe_from_db(id)
return render_template('recipe.html', recipe=recipe)
您可能还想保留 get_with_title()
路由,以防用户 bookmark/share URL(包括标题)并希望它可以访问(否则,访问时会返回“Not Found”错误。
选项 2
如果您不希望每次收到新请求时都查询数据库——甚至不希望检索菜谱条目的 title
(不是每一列)——并且您有足够的内存来保存数据,我建议在启动时查询一次数据库(只选择id
和title
)并创建一个字典,这样你就可以快速查找一个title
来自食谱 id
。请注意,以这种方式,每次对 table 执行 INSERT/DELETE/etc 操作时,必须相应地更新该字典。因此,如果您经常在 table 上进行此类操作,可能不是解决问题的最佳方法,最好继续查询 table 只是为了检索 title
.
recipes = dict((row[0], row[1]) for row in result) # where row[0] is id and row[1] is title
然后在您的端点:
@app.route('/recipe/<int:id>', methods=['GET'])
def get(id):
title = recipes.get(id)
return redirect(url_for('get_with_title', id=id, title=urlify(title)))