[英]How to serve, reference, and save static files in Flask/python app.py or views.py files, avoiding FileNotFound errors
與this question類似,但我有一些跟進。 如何在 Flask 中提供靜態文件
我在調整上.savefig()
文章中的解決方案時遇到的主要問題是,我需要使用 matplotlib 的.savefig()
函數,該函數只接收一個字符串作為要保存到的路徑。 所以我需要知道要傳遞什么字符串。
我記得當我第一次在本地處理我的 Flask 應用程序時,靜態文件有很多問題。 我不知道我應該如何正確地引用從我的靜態文件的路徑app.py
/ views.py
Python文件。 我理解在 html 中使用url_for()
而不是,但是在 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()
它接受一條路徑,但我仍然無法弄清楚我應該如何編寫這條路徑。
在此之前,我已經設法讓靜態文件正常工作。 我不得不將上面對靜態文件的兩個引用更改為以下內容:
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
變量嗎? 編輯: 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
寫入 Bytes 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
目錄位於頂層。 所以,你需要提供相對於其中這樣的說法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 = {}
# ...
考慮flask 關於如何組織flask 應用程序的文檔。 他們談論的第一個文件結構是“簡單模塊”模式,第二個文件結構是更復雜的“包”模式。 https://flask.palletsprojects.com/en/1.1.x/tutorial/layout/
我最初試圖引入“簡單模塊”模式。 app_dir
的內容是空的。 相反, Neuroethics_Behavioral_Task
是我的項目目錄,和它的1個里面是我的experiment.py
, __init__.py
, /static/
和/templates/
文件夾。
通過為我的 Flask 應用程序切換到基於包的組織模式,我能夠克服這些 FileNotFound 錯誤。 所以文件結構現在看起來像
在這個方案中, Neuroethics_Behavioral_Task
仍然是項目目錄。 但是現在有app_dir
包含__init.py__
, experiment.py
, /static/
和/template/
都在同一目錄下。
當我做出這個改變時,我能夠將experiment.py
大部分save()語句改寫成這樣。
# inside of generate_stim_for_trials()
csv_path = "app_dir/static/textdata/" + subj_id + "_data.csv"
換句話說,我所要做的就是使用 app_dir 前綴。
這在我的本地機器上都有效,並且在我將代碼推送到 heroku 后也有效。 我仍在使用這種基於“包”的組織模式,因為它至少是flask 推薦用於復雜應用程序的。
另一方面,V25 提出了一個非常關鍵的觀點,即 Heroku 不提供永久存儲,如果您像我一樣將東西部署到 heroku,這可能會完全改變您的計划。 我很高興我提到我打算這樣做。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.