python - 如何在 Flask/python app.py 或 views.py 文件中提供、引用和保存静态文件,避免 FileNotFound 错误
问题描述
类似于这个问题,但我有一些后续行动。如何在 Flask 中提供静态文件
我在调整上一篇文章中的解决方案时遇到的主要问题是我需要使用 matplotlib 的.savefig()
函数,它只接受一个字符串作为保存路径。所以我需要知道传递什么字符串。
我记得当我第一次在本地处理我的 Flask 应用程序时,我遇到了很多关于静态文件的问题。我不知道我应该如何从我的app.py
/ views.py
python 文件中正确引用静态文件的路径。我了解url_for()
在 html 中使用什么,但在 python 中引用静态文件并不那么简单。
我的烧瓶应用程序具有以下结构。根目录称为Neuroethics_Behavioral_Task
我有一个名为的文件experiment.py
,该文件基本上是一个views.py
或app.py
文件。但我似乎找不到引用静态文件的正确方法。
这是experiment.py
代码。
import functools
from flask import (
Blueprint, flash, g, redirect, render_template, request, session, url_for, Flask
)
from werkzeug.security import check_password_hash, generate_password_hash
app = Flask(__name__, instance_relative_config=True, static_url_path='') # creates the flask instance
bp= Blueprint('experiment', __name__)
@app.route('/')
@app.route('/index')
def index():
return render_template("welcome.html")
@app.route('/experiment_app', methods=['GET', 'POST'])
def exp_js_psych_app():
total_trials = int(request.form['trials'])
import random
import string
user_id = ''.join([random.choice(string.ascii_letters
+ string.digits) for n in range(8)])
user_id = str(user_id)
stim_metadata = generate_stim_for_trials(total_trials, user_id)
return render_template("index.html", data={"user_id": str(user_id), "total_trials":total_trials, "lst_of_stim_jsons":stim_metadata})
def generate_stim_for_trials(trials, uid):
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import json
import os
json_dict = {}
json_dict["stimuli path info"] = []
lst_of_jsons_for_stimuli = []
# Unused but problematic static reference.
stim_metadata_path = "/static/textdata/stimulus_data" + str(uid) + ".json"
# Another problematic static reference.
stimuli_path = '/static/images/stimulus_img' + 1 + ".png"
df = pd.DataFrame({"Risk":[25], "No Effect" : [50], "Gain":[25]})
df.plot(kind='barh', legend = False, stacked=True, color=['#ed713a', '#808080', '#4169e1'])
plt.axis('off')
plt.gca().set_axis_off()
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, hspace = 0, wspace = 0)
plt.ylim(None,None)
plt.autoscale()
plt.margins(0,0)
plt.savefig(stimuli_path) # this fails
需要注意的是,将static_url_path
参数传递给Flask()
调用并没有真正按预期工作,我认为这会将根目录建立为首先查找我的静态文件的位置,但该代码仍然失败的事实表明否则,因为我的/static/
目录显然在根文件夹中。
否则,正如我所说...我需要使用plt.savefig()
which 接受路径,但我仍然无法弄清楚我应该如何编写这条路径。
在此之前,我已经设法让静态文件正常工作。我不得不将上面对静态文件的两个引用更改为以下内容:
stimuli_path = 'Neuroethics_Behavioral_Task/static/images/stimulus_img' + "1" + ".png"
stim_metadata_path = "Neuroethics_Behavioral_Task/static/textdata/stimulus_data" + str(uid) + ".json"
换句话说,我可以通过在路径中包含根目录来获取静态文件。
这至少让我度过了......直到我尝试将我的应用程序部署到 Heroku 上。然后我开始收到Neuroethics_Behavioral_Task/static/images/
不是可识别路径的错误......所以现在我觉得我需要真正开始正确地引用静态文件,我现在不知道如何去做。
我尝试了变体(例如:)images/stimulusimg1.png
并尝试更改static_url_path
参数(例如:)static_url_path='/static/
,但这些都只是导致我的 Flask 应用程序在本地崩溃说 FileNotFound。
我有另一个重要的后续问题......
该应用程序将在 Amazon Mechanical Turk 上发布在线实验。图像应该由我正在使用的名为 JsPsych 的框架预加载。但是像这样的帖子和我第一次包含的帖子鼓励您使用 NGINX提供文件“提供静态文件”到底是什么意思?
我不知道 Nginx 或 wsgi 是如何工作的。我是否还应该费心尝试以这种方式提供所有静态文件,如果是,我该如何开始?
总而言之,我要问的问题是
- 我需要将静态文件保存在我的
experiment.py
//文件中views.py
,apps.py
因此我需要找出实际表示静态图像路径的字符串。我怎么做?我真的需要修改static_url_path
变量吗? - 为什么我以前成功地在静态文件的路径中引用了根目录
- 我的图像应该由我正在使用的 JavaScript 框架 JsPsych 预加载。我还应该经历设置 nginx 和 wsgi 配置的麻烦吗?
编辑:url_for()
也不工作。
stimuli_in_static = "images/stimulus_img" + "1" + ".png"
stimuli_path = url_for('static', filename=stimuli_in_static)
这仍然会导致.savefig()
调用时出现 FileNotFound 错误,
FileNotFoundError: [Errno 2] No such file or directory: '/static/images/stimulus_img1.png'
解决方案
根据我的评论,因为 Heroku 不支持持久文件系统存储,所以推荐的方法是使用 S3。为此,您需要plot.fig
写入字节 IO 缓冲区,然后将其上传到 S3。这个过程包含在这个 SO 线程中。
无论哪种方式,这都是关于静态文件内容的答案,这在 Heroku 上是允许的,前提是所讨论的静态文件实际上是 repo 的一部分(javascript 和 CSS 文件等)......
static_url_path
旨在更改静态文件可用的 URL。这会影响提供静态文件的前端 URL路径。
使用以下配置静态文件可用,http://example.com/apple/
无论它们在文件系统上的什么位置:
app = Flask(__name__, static_url_path='apple')
如果要定义 Flask 在文件系统中查找静态文件的位置,请static_folder
改用。在您的情况下,应用程序位于app_dir/experiment.py
并且您的static
目录位于顶层。因此,您需要提供与 where 相关experiment.py
的参数:
app = Flask(__name__, static_folder='../static')
就我个人而言,我试图消除这整个头痛并创建一个符合 Flask 默认期望的目录结构:
project
├── experiment.py
├── static
│ └── some.js
└── templates
└── some.html
关于您的代码的另一个提示:
def generate_stim_for_trials(trials, uid):
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import json
import os
这是低效的,因为每次调用该函数时都会加载所有这些导入。
你真的想把这些导入放在文件的顶部,这样它们就会在应用服务器运行时加载,然后才加载。:
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import json
import os
# ...
def generate_stim_for_trials(trials, uid):
json_dict = {}
# ...
推荐阅读
- reactjs - 在其他设备上直播 netlify 应用程序黑屏
- vb.net - iText 7签名字段对齐
- javascript - 如何在 node.js 中定义要观看的多种文件类型
- arcore - 我是否需要为 AR 应用程序开发安装 Google Play 服务
- jquery - JQuery on_click: removeClass in a button then toggleClass another (只有一个按钮有类)
- javascript - 我收到此错误 DiscordAPIError: Invalid Form Body
- typescript - 如何解决问题没有找到 exportAs 'matAutocomplete' 的指令?
- python - 我似乎无法让我的两只眼睛为 Turtle 工作
- ruby-on-rails - 返回已归档对象的所有关系的活动记录:false
- c# - 如何使用 post 方法在 ASP.net core MVC 中显示内容