python - Flask:从一个路由/函数访问或传递字典到另一个路由/函数

标签 python dictionary flask global

主页是一个表单,然后当用户单击“计算”时,会根据表单进行计算,并将其存储在字典中,然后传回以填充表格。简要如下:

@app.route('/join', methods=['GET','POST'])
def my_form_post():
---calculations done and variables set---

data_dict = {
        "loco_length":l1, "loco_weight":w1, "loco_bweight":b1,
        "cargo_length":l2, "cargo_weight":w2, "cargo_bweight":b2,
        "total_length":length, "total_weight": weigth, "total_bweight": bweigth,
        "bproc":bproc
    }

    result = {str(key): value for key, value in data_dict.items()}
    return jsonify(result=result)

但是后来我创建了第二个函数,我希望通过新路线/pdf 来访问它。 该功能是用“my_form_post”字典中的值填充预定义的 PDF 模板。

第二条路线如下所示,调用函数并需要字典作为参数:

def pdf():

    data = write_fillable_pdf(PDF_TEMP_PATH, data_dict)
    return send_file(data, mimetype='application/pdf')

如何让字典在函数和路由之间传输或访问?我见过人们提到 session 、json 和全局变量。但我想不通。

感谢您的帮助。

最佳答案

好的,正如我提到的,一个非常酷的后端是 Redis。当您在 PythonAnywhere 上托管时,实际上有一个名为 redislite 的库。它将使用本地文件而不是实际的 Redis 服务器来提供此功能。

出现PythonAnywhere,don't support redis但是do support persistant storage 。更好的是,如果您稍后移动到具有实际 Redis 服务器的主机,则应该只需修改两行即可切换。

其背后的概念是:

  • /join路由,创建一个 UUID 用作 unique_id并将其与 dict 一起存储在 redis 中,然后传递 unique_id返回模板,将其作为链接呈现给用户。
  • /pdf路线,根据unique_id从redis获取dict在 URL 字符串中。
  • 为了获得奖励积分,我们可以在 redis key 上设置过期时间,因此在 n 之后几秒钟后,链接就会消失,用户必须再次点击计算按钮。

首先您需要添加 redislite符合要求,或pip install redislite 。然后在 Python 文件的顶部包含配置 Redis 连接所需的内容:

from redislite import StrictRedis
import os
REDIS_DB_PATH = os.path.join('/tmp/my_redis.db')
r = StrictRedis(REDIS_DB_PATH, charset='utf-8', decode_responses=True)

您还应该定义到期时间,一个使 redis 键对于这组路由保持唯一的前缀,并导入其他工具:

PDF_EXPIRY = 60*60*24 # 1 day in seconds
PREFIX = 'pdf:' # A prefix for our redis keys
from uuid import uuid4
from flask import url_for

现在下一部分可以工作了,因为您的数据是一个简单的字典,没有嵌套。我在这里使用了模拟版本,然后使用hmset将其添加到redis中并设置到期时间。

然后我添加 key pdf_link给您result dict 并将值设置为由 Flask 构建的 PDF 的 URL url_for功能:

@app.route('/join')
def my_form_post():

    # ---calculations done and variables set---

    data_dict = {
        "loco_length":3.14, "loco_weight":'str', "loco_bweight":'str',
    } # a simplified version of your dictionary

    unique_id = uuid4().__str__()

    r.hmset(PREFIX + unique_id, data_dict)
    r.expire(PREFIX + unique_id, PDF_EXPIRY)

    result = {str(key): value for key, value in data_dict.items()}

    # This creates a URL back to our PDF route, as a key in result
    result['pdf_link'] = url_for('pdf',unique_id = unique_id)  

    return jsonify(result=result)

这会产生一个带有 key 的 Redis 哈希:pdf:86341e77-f655-46d8-93c4-10e945fc3586和字段名称/值,如您的 data_dict的键/值。请参阅 HMSET redis docs对此的另一个可视化。

现在在前端result.pdf_link是 PDF 的有效链接,类似于:/pdf/86341e77-f655-46d8-93c4-10e945fc3586 。您可以将其呈现在 <a href=> 中模板上表格旁边的标签。

对该 URL 的请求由下一个路由处理:

@app.route('/pdf/<string:unique_id>')
def pdf(unique_id):
    data_dict = r.hgetall(PREFIX + unique_id)
    if not data_dict:
        return 'Not found or expired', 404
    else:
        data = write_fillable_pdf(PDF_TEMP_PATH, data_dict)
        return send_file(data, mimetype='application/pdf')

我认为这种方法非常干净,因为它避免了为数据构建数据库模型,而这本来是常见的方法。这样,您可以向 data_dict 添加更多值,只要你不嵌套它们,其他什么都不需要改变。

如果您将来想添加对真正的 Redis 服务器的支持,只需将这两行更改为:

from redis import StrictRedis
r = StrictRedis(host='newredisserver', charset='utf-8', decode_responses=True)

因为我们使用的方法在 redis 之间是相同的和redislite图书馆。

请注意,任何拥有 PDF 链接的人都可以下载该 PDF,前提是该 PDF 尚未过期,因此您可能不应该在未经身份验证的情况下通过此方式传递个人信息

关于python - Flask:从一个路由/函数访问或传递字典到另一个路由/函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59934360/

相关文章:

Python Flask Angular 应用程序状态不刷新

Python Pandas : if date1 == 0, 从 date2 复制

python - Mechanize 提交表单错误: Insufficient items with name '10427'

ios - Swift 3 - 将数组缩减为具有唯一元素计数的字典

flask - 使用从上一个字段中选择的值填充 WTForms 选择字段

python - 对 Docker 化 Flask 应用程序进行单元测试时出现断言错误(200 成功!= 400 错误请求)

python - Python 中的 Q : Expected number of coin tosses to get N heads in a row,。我的代码给出的答案与已发布的正确答案不匹配,但不确定原因

Python 的 ProcessPoolExecutor 以相反的顺序给出 print 和 return 语句的输出

json - 来自单列中嵌套字典的 Pandas 数据框

python - 根据匹配值合并 2 个字典列表,否则保持原始?