【问题标题】:Flask: Accessing or Passing a dictionary from one route/function to another [duplicate]Flask:从一个路由/函数访问或传递字典到另一个[重复]
【发布时间】:2020-05-13 00:27:24
【问题描述】:

主页是一个表单,然后当用户单击“计算”时,会从表单进行计算,存储在字典中,然后传回以填充表格。简而言之:

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

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

感谢您的帮助。

【问题讨论】:

  • 你有(/你能得到)访问 Redis 服务器的权限吗?我想用 redis 写一个答案...
  • 我不确定,我将它托管在 pythonanywhere.com atm 但希望将来会在我自己的云 nginx+gunicorn 上托管它。我希望它尽可能简单,字典很小,只有偶尔想要将其打印为 PDF 的用户才需要它。

标签: python dictionary flask global


【解决方案1】:

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

它出现在 PythonAnywhere,don't support redisdo support persistant storage。更好的是,如果你以后搬到有实际redis服务器的主机上,应该是两行修改才能切换。

这背后的概念是:

  • /join 路由中,创建一个UUID 用作unique_id 并将其与dict 一起存储在redis 中,然后将unique_id 传递回模板,将其作为链接呈现给用户。
  • /pdf路由中,根据URL字符串中的unique_id从redis中获取dict。
  • 对于奖励积分,我们可以在 redis 键上设置一个过期时间,因此在 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并设置到期时间。

然后我将键 pdf_link 添加到您的 result dict 并将值设置为 PDF 的 URL,由 flask 的 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)

这会产生一个带有键的 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)

因为我们使用的方法在 redisredislite 库之间是相同的。

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

【讨论】:

  • 这是一篇相当广泛的文章,谢谢!我还没有时间尝试它,但我不知道它是如何工作的。在 /join 路由中,结果被发送回前端,以将字典加载到我提供的 html 表中。我不想搞砸这一点,Pdf 创建不是必需的,而是可选的,并且需要字典中的值。
  • @mag37 Redis 充当键值存储,可从应用程序的任何部分访问。您定义存储结构。因此,当您将hmset 与第一个参数PREFIX+uniquie_id 一起使用时,只要您提供相同的密钥,您就可以从任何地方取回它。通过使用url_for 生成链接,使您能够supply /pdf/&lt;string:unique_id&gt; 路由中的相同键。因此,hmgetall 可以检索字典并生成 PDF,如果用户单击带有该unique_id 的链接。
  • 感谢您的解释!当我有时间真正了解它时,我会试一试;)兼顾一份全职工作和一个 2 岁的孩子,这是我的第一个编程项目 - 鸽子太深了! ^^
  • @mag37 不错,很高兴听到!如有更多问题,请随时在这里提问,因为我每天都会关注我的通知 :-)
  • 抱歉垃圾邮件 - 但我通过使用 werkzeug - FileWrapper 和 Flask 的响应解决了这个问题,如下示例:pythonanywhere.com/forums/topic/13570
猜你喜欢
  • 2020-01-10
  • 2017-03-31
  • 1970-01-01
  • 1970-01-01
  • 2017-08-16
  • 1970-01-01
  • 2020-05-03
  • 2021-03-07
  • 1970-01-01
相关资源
最近更新 更多