Flaskで静的ファイルを提供する方法


539

これは恥ずかしいことです。私は一緒に投げ込んだアプリケーションを手に入れましたが、Flask今のところは、CSSとJSへのリンクを含む単一の静的HTMLページを提供しているだけです。そして、ドキュメントのどこにFlask静的ファイルを返すかがわかりません。はい、使用できますrender_templateが、データがテンプレート化されていません。私は思っていた、send_fileまたはurl_for正しいことでしたが、それらを機能させることができませんでした。その間、私はファイルを開き、コンテンツを読み取りResponse、適切なMIMEタイプでリギングします。

import os.path

from flask import Flask, Response


app = Flask(__name__)
app.config.from_object(__name__)


def root_dir():  # pragma: no cover
    return os.path.abspath(os.path.dirname(__file__))


def get_file(filename):  # pragma: no cover
    try:
        src = os.path.join(root_dir(), filename)
        # Figure out how flask returns static files
        # Tried:
        # - render_template
        # - send_file
        # This should not be so non-obvious
        return open(src).read()
    except IOError as exc:
        return str(exc)


@app.route('/', methods=['GET'])
def metrics():  # pragma: no cover
    content = get_file('jenkins_analytics.html')
    return Response(content, mimetype="text/html")


@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def get_resource(path):  # pragma: no cover
    mimetypes = {
        ".css": "text/css",
        ".html": "text/html",
        ".js": "application/javascript",
    }
    complete_path = os.path.join(root_dir(), path)
    ext = os.path.splitext(path)[1]
    mimetype = mimetypes.get(ext, "text/html")
    content = get_file(complete_path)
    return Response(content, mimetype=mimetype)


if __name__ == '__main__':  # pragma: no cover
    app.run(port=80)

誰かがこれのコードサンプルまたはURLを提供したいですか?これは簡単なことです。


6
静的ファイルを提供するためにnginxまたは他のWebサーバーを使用しないのはなぜですか。
atupal 2013

8
実際にファイルを「提供」する方法は、本番(Webサーバー上)と開発(ローカルコンピューター上、またはその他のテスト領域)で異なる可能性があることに注意してください。いくつかの回答が指摘しているように、おそらくフラスコで静的ファイルを提供するのではなく、それらを独自のディレクトリに置いて、実際のWebサーバー(Apache、nginxなど)がそれらのファイルを直接サーバーで処理するようにします。
Mark Hildreth、


75
「なぜnginxを使わないのか…」私のラップトップで開発者モードで実行しているときは、1つのことだけを実行するだけで十分です。はい、それは少し物事が異なりますが、それは大丈夫です。
タナトス2016年

1
本番環境であっても、もちろんキャッシュレイヤーが前面にある(VarnishやNginx、CDNなど)ことを確認するのは非常に一般的です。
トーマスデコー

回答:


643

推奨される方法は、nginxまたは別のWebサーバーを使用して静的ファイルを提供することです。彼らはFlaskよりも効率的にそれを行うことができるでしょう。

ただし、を使用send_from_directoryしてディレクトリからファイルを送信できます。これは、状況によっては非常に便利です。

from flask import Flask, request, send_from_directory

# set the project root directory as the static folder, you can set others.
app = Flask(__name__, static_url_path='')

@app.route('/js/<path:path>')
def send_js(path):
    return send_from_directory('js', path)

if __name__ == "__main__":
    app.run()

ではない使用send_filesend_static_fileユーザー提供のパスを持ちます。

send_static_file 例:

from flask import Flask, request
# set the project root directory as the static folder, you can set others.
app = Flask(__name__, static_url_path='')

@app.route('/')
def root():
    return app.send_static_file('index.html')

12
Windowsをサポートするには:app.send_static_file(os.path.join( 'js'、path).replace( '\\'、 '/'))を
返します

9
攻撃者はこのメソッドを悪用して、/ js /のような<../ yourflaskapp.py ">の巧妙なエンコーディングを参照して、フラスコのソースファイルを閲覧できますか?
akiva 2014

30
@kiwi send_from_directoryはそのセキュリティ問題を解決するように設計されています。パスが特定のディレクトリの外部に通じている場合にエラーを出すために存在します。
jpmc26 2014

10
「ユーザー指定のパスでsend_fileまたはsend_static_fileを使用しないでください。」何故なの?
Drew Verlee、2015

6
@DenisVこれはPython自体とは何の関係もありません。URLパラメータを定義するためのFlaskの規則です(http://flask.pocoo.org/docs/0.12/api/#url-route-registrationsを参照)。一言で言えば、はと<path>同等<string:path>であり、Flaskで要求するパスのようなパラメータを確保するため<path:path>です。
b4stien 2017年

135

静的ファイルの場所を移動するだけの場合、最も簡単な方法は、コンストラクターでパスを宣言することです。以下の例では、テンプレートと静的ファイルをというサブフォルダーに移動しましたweb

app = Flask(__name__,
            static_url_path='', 
            static_folder='web/static',
            template_folder='web/templates')
  • static_url_path=''URLから先行するパスをすべて削除します(つまり、デフォルトの/static)。
  • static_folder='web/static'フォルダー内で見つかった web/staticファイルを静的ファイルとして提供します。
  • template_folder='web/templates' 同様に、これはテンプレートフォルダーを変更します。

このメソッドを使用すると、次のURLはCSSファイルを返します。

<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">

そして最後に、ここにフォルダー構造のスナップがありますflask_server.py。Flaskインスタンスは次のとおりです。

ネストされた静的フラスコフォルダ


9
これは私にとってもうまくいきました。Send_from_directoryは、すべての推奨事項にもかかわらず機能しませんでした。
GA

完璧に動作します。本当にありがとうございました。
Thuat Nguyen

パスはどのように見えますか?get_static_file('index.html')
バットマン

GAが言ったように、これはうまく機能し、他には何も機能せず、これですべてが修正されました。
とても

81

また、これは私のお気に入りです。フォルダを静的パスとして設定し、内部のファイルに誰もがアクセスできるようにします。

app = Flask(__name__, static_url_path='/static')

このセットを使用すると、標準のHTMLを使用できます。

<link rel="stylesheet" type="text/css" href="/static/style.css">

4
project/static/style.css利用可能なファイルがあればうまくいきます。
Pavel Vlasov

6
行「app = Flask(....)」も「static_folder」をパラメータにする必要があります
datdinhquoc

私はこの問題に何時間も苦労しています!私は単一の引数を見逃していました!
LogicalBranch

78

私はあなたがそこに必要なものを見つけると確信しています:http : //flask.pocoo.org/docs/quickstart/#static-files

基本的には、パッケージのルートに「静的」フォルダーが必要なだけで、http://example.com/static/foo.barurl_for('static', filename='foo.bar')を使用して、またはファイルに直接リンクできます。

EDIT:としては、あなたが直接使用することができ、コメントで提案されている'/static/foo.bar'URLパスをBUT url_for()オーバーヘッド(パフォーマンスは賢明な)非常に低く、それはあなたが簡単に後から動作をカスタマイズできるようになりますことを意味使用して(、URLのパスを変更、フォルダを変更静的ファイルをS3などに移動します)。


14
なぜ'/static/foo.bar'直接しないのですか?
タイラーロング

3
@TylerLongは正しいです。静的ディレクトリに既に保存されているファイルにリンクしたい場合は、ルートコードなしでファイルに直接リンクできます。
hamx0r 2014

42

次の関数を使用できます。

send_static_file(filename)
静的ファイルを静的フォルダーからブラウザーに送信するために内部的に使用される関数。

app = Flask(__name__)
@app.route('/<path:path>')
def static_file(path):
    return app.send_static_file(path)

1
これは、大きな頭痛の種なしで私のために働いた唯一のものでした。
ケニーパワーズ

同じ。Flashは、HTMLが他の場所で作成されるRIAではなく、テンプレートシステムを使用するという考えに大きく依存しています。
NiKo、2017年

15
警告:これは、send_static_fileユーザー入力で呼び出すにはセキュリティ上の大きな問題です。このソリューションを重要なものに使用しないでください。
xApple

41

私が使用しているもの(そしてそれがうまく機能しているもの)は、「テンプレート」ディレクトリと「静的」ディレクトリです。私はすべての.htmlファイル/ Flaskテンプレートをテンプレートディレクトリ内に配置し、静的にはCSS / JSが含まれています。render_templateは、Flaskのテンプレート構文をどの程度使用したかに関係なく、私の知る限り、一般的なhtmlファイルで正常に機能します。以下は、私のviews.pyファイルのサンプル呼び出しです。

@app.route('/projects')
def projects():
    return render_template("projects.html", title = 'Projects')

別の静的ディレクトリにある静的ファイルを参照する場合は、url_for()を使用してください。おそらく、HTMLのCSS / JSファイルリンクでこれを行うことになります。例えば...

<script src="{{ url_for('static', filename='styles/dist/js/bootstrap.js') }}"></script>

「正規の」非公式のFlaskチュートリアルへのリンクは次のとおりです。ここには、着実に実行するのに役立つ多くの優れたヒントがあります。

http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world


38

他の回答に基づく最も単純な実際の例は次のとおりです。

from flask import Flask, request
app = Flask(__name__, static_url_path='')

@app.route('/index/')
def root():
    return app.send_static_file('index.html')

if __name__ == '__main__':
  app.run(debug=True)

index.htmlというHTMLの場合:

<!DOCTYPE html>
<html>
<head>
    <title>Hello World!</title>
</head>
<body>
    <div>
         <p>
            This is a test.
         </p>
    </div>
</body>
</html>

重要:そしてindex.htmlのが呼ばれるフォルダ内にある静的な、意味が<projectpath>あり.py、ファイルを、と<projectpath>\static持っているhtmlファイルを。

サーバーをネットワーク上で見えるようにしたい場合は、 app.run(debug=True, host='0.0.0.0')

編集:必要に応じてフォルダー内のすべてのファイルを表示するには、これを使用します

@app.route('/<path:path>')
def static_file(path):
    return app.send_static_file(path)

これは本質的にBlackMambaの答えなので、賛成投票をしてください。


重要な観察をありがとう!
グライドソンカルドソダシルバ

13

次のフォルダツリーを作成するangular + boilerplateフローの場合:

backend/
|
|------ui/
|      |------------------build/          <--'static' folder, constructed by Grunt
|      |--<proj           |----vendors/   <-- angular.js and others here
|      |--     folders>   |----src/       <-- your js
|                         |----index.html <-- your SPA entrypoint 
|------<proj
|------     folders>
|
|------view.py  <-- Flask app here

私は次の解決策を使用します:

...
root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ui", "build")

@app.route('/<path:path>', methods=['GET'])
def static_proxy(path):
    return send_from_directory(root, path)


@app.route('/', methods=['GET'])
def redirect_to_index():
    return send_from_directory(root, 'index.html')
...

「静的」フォルダをカスタムに再定義するのに役立ちます。


あなたの答えに基づいて私はこれを行いました:stackoverflow.com/a/29521067/303114 注意:基本的に同じ 'add_url_rule' intead 'route'を使用しました
danfromisrael

7

だから私は(@ user1671599の回答に基づいて)問題なく機能し、それを皆さんと共有したいと思いました。

(私はそれがPythonでの最初のアプリであるため、私はそれが正しく行われていることを願っています)

これは私がしました -

プロジェクトの構造:

ここに画像の説明を入力してください

server.py:

from server.AppStarter import AppStarter
import os

static_folder_root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "client")

app = AppStarter()
app.register_routes_to_resources(static_folder_root)
app.run(__name__)

AppStarter.py:

from flask import Flask, send_from_directory
from flask_restful import Api, Resource
from server.ApiResources.TodoList import TodoList
from server.ApiResources.Todo import Todo


class AppStarter(Resource):
    def __init__(self):
        self._static_files_root_folder_path = ''  # Default is current folder
        self._app = Flask(__name__)  # , static_folder='client', static_url_path='')
        self._api = Api(self._app)

    def _register_static_server(self, static_files_root_folder_path):
        self._static_files_root_folder_path = static_files_root_folder_path
        self._app.add_url_rule('/<path:file_relative_path_to_root>', 'serve_page', self._serve_page, methods=['GET'])
        self._app.add_url_rule('/', 'index', self._goto_index, methods=['GET'])

    def register_routes_to_resources(self, static_files_root_folder_path):

        self._register_static_server(static_files_root_folder_path)
        self._api.add_resource(TodoList, '/todos')
        self._api.add_resource(Todo, '/todos/<todo_id>')

    def _goto_index(self):
        return self._serve_page("index.html")

    def _serve_page(self, file_relative_path_to_root):
        return send_from_directory(self._static_files_root_folder_path, file_relative_path_to_root)

    def run(self, module_name):
        if module_name == '__main__':
            self._app.run(debug=True)

より良い理解のためにあなたはこの答えを読むことができます:stackoverflow.com/a/23501776/303114 (githubのソースを示します)
danfromisrael

6

簡単な方法の1つ。 乾杯!

demo.py

from flask import Flask, render_template
app = Flask(__name__)

@app.route("/")
def index():
   return render_template("index.html")

if __name__ == '__main__':
   app.run(debug = True)

次に、templatesという名前のフォルダー名を作成します。テンプレートフォルダー内にindex.htmlファイルを追加します

index.html

<!DOCTYPE html>
<html>
<head>
    <title>Python Web Application</title>
</head>
<body>
    <div>
         <p>
            Welcomes You!!
         </p>
    </div>
</body>
</html>

プロジェクトの構造

-demo.py
-templates/index.html

あなたは質問を読みませんでした。render_template解決策は知っていたが、代わりのファイルがなく静的だったため、そうしたくなかったと明確に述べた。「はい、render_templateを使用できますが、データがテンプレート化されていません。」
hughdbrown

Windowsで簡単に機能する唯一のソリューション、ありがとう!
Basj

4

共有の考え....この例。

from flask import Flask
app = Flask(__name__)

@app.route('/loading/')
def hello_world():
    data = open('sample.html').read()    
    return data

if __name__ == '__main__':
    app.run(host='0.0.0.0')

これはより簡単に機能します。


これがどのように機能するかを詳しく説明していただけますか?
arsho

1
lmaoの他のすべての方法では、迷惑なファイルが見つからないというエラーが発生しました。nice1 jeevan
Dmitri DB

3

使用redirectしてurl_for

from flask import redirect, url_for

@app.route('/', methods=['GET'])
def metrics():
    return redirect(url_for('static', filename='jenkins_analytics.html'))

これは、htmlで参照されるすべてのファイル(css&js ...)を処理します。


2

最も簡単な方法は、メインプロジェクトフォルダー内に静的フォルダーを作成することです。.cssファイルを含む静的フォルダー。

メインフォルダー

/Main Folder
/Main Folder/templates/foo.html
/Main Folder/static/foo.css
/Main Folder/application.py(flask script)

静的フォルダーとテンプレートフォルダー、およびフラスコスクリプトを含むメインフォルダーの画像

フラスコ

from flask import Flask, render_template

app = Flask(__name__)

@app.route("/")
def login():
    return render_template("login.html")

html(レイアウト)

<!DOCTYPE html>
<html>
    <head>
        <title>Project(1)</title>
        <link rel="stylesheet" href="/static/styles.css">
     </head>
    <body>
        <header>
            <div class="container">
                <nav>
                    <a class="title" href="">Kamook</a>
                    <a class="text" href="">Sign Up</a>
                    <a class="text" href="">Log In</a>
                </nav>
            </div>
        </header>  
        {% block body %}
        {% endblock %}
    </body>
</html>

html

{% extends "layout.html" %}

{% block body %}
    <div class="col">
        <input type="text" name="username" placeholder="Username" required>
        <input type="password" name="password" placeholder="Password" required>
        <input type="submit" value="Login">
    </div>
{% endblock %}

2
app = Flask(__name__, static_folder="your path to static")

ルートディレクトリにテンプレートがある場合、これを含むファイルも同じ場所にある場合はapp = Flask(name)を配置できます。このファイルが別の場所にある場合は、有効にするテンプレートの場所を指定する必要があります場所を指すフラスコ


4
これが機能する理由を説明していただけますか?
経済

1
説明を提供するこの回答とどう違うのですか?
ジノメンピン

私の回答@economy
Novak254の

1

すべての答えは良いですが、私にとってうまくいったのはsend_file、Flaskの単純な関数を使用することだけです。これは、host:port / ApiNameがブラウザでファイルの出力を表示するときに、応答としてhtmlファイルを送信する必要がある場合にうまく機能します


@app.route('/ApiName')
def ApiFunc():
    try:
        return send_file('some-other-directory-than-root/your-file.extension')
    except Exception as e:
        logging.info(e.args[0])```

0

   デフォルトでは、フラスコは「テンプレート」フォルダを使用してすべてのテンプレートファイル(プレーンテキストファイルですが、通常.htmlまたはjinja2などのある種のテンプレート言語)と「静的」フォルダを使用してすべての静的ファイル(.js .cssおよびあなたの画像)。
   でroutes、uを使用render_template()して、templatesリクエストに対する応答としてテンプレートファイル(上記で言ったように、デフォルトではフォルダーに配置されます)をレンダリングできます。そして、テンプレートファイル(通常は.htmlのようなファイルです)では、いくつか.jsのファイルや `.css 'ファイルを使用する可能性があるため、これらの静的ファイルを現在のテンプレートファイルにリンクする方法が問題だと思います。


0

ファイルを開こうとしているだけなら、を使用できます app.open_resource()。したがって、ファイルを読み取ると、次のようになります。

with app.open_resource('/static/path/yourfile'):
      #code to read the file and do something
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.