簡體   English   中英

如何在 Flask/python app.py 或 views.py 文件中提供、引用和保存靜態文件,避免 FileNotFound 錯誤

[英]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.pyapp.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變量嗎?
  • 為什么我以前在靜態文件的路徑中引用根目錄是成功的
  • 我的圖像應該由我正在使用的 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寫入 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM