Python 如何在 Flask 中提供静态文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20646822/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 20:56:15  来源:igfitidea点击:

How to serve static files in Flask

pythonflaskstatic-files

提问by hughdbrown

So this is embarrassing. I've got an application that I threw together in Flaskand for now it is just serving up a single static HTML page with some links to CSS and JS. And I can't find where in the documentation Flaskdescribes returning static files. Yes, I could use render_templatebut I know the data is not templatized. I'd have thought send_fileor url_forwas the right thing, but I could not get those to work. In the meantime, I am opening the files, reading content, and rigging up a Responsewith appropriate mimetype:

所以这很尴尬。我有一个应用程序,我把它放在一起,Flask现在它只是提供一个单一的静态 HTML 页面,其中包含一些指向 CSS 和 JS 的链接。而且我在文档Flask中找不到描述返回静态文件的地方。是的,我可以使用,render_template但我知道数据不是模板化的。我本来想send_file或者url_for是正确的事情,但我无法让这些工作。与此同时,我正在打开文件,阅读内容,并Response使用适当的 mimetype装配一个:

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)

Someone want to give a code sample or url for this? I know this is going to be dead simple.

有人想为此提供代码示例或网址吗?我知道这将非常简单。

采纳答案by atupal

The preferred method is to use nginx or another web server to serve static files; they'll be able to do it more efficiently than Flask.

首选方法是使用 nginx 或其他 Web 服务器来提供静态文件;他们将能够比 Flask 更有效地做到这一点。

However, you can use send_from_directoryto send files from a directory, which can be pretty convenient in some situations:

但是,您可以使用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()

Do notuse send_fileor send_static_filewith a user-supplied path.

千万不能使用send_filesend_static_file与用户提供的路径。

send_static_fileexample:

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

回答by b4stien

I'm sure you'll find what you need there: http://flask.pocoo.org/docs/quickstart/#static-files

我相信你会在那里找到你需要的东西:http: //flask.pocoo.org/docs/quickstart/#static-files

Basically you just need a "static" folder at the root of your package, and then you can use url_for('static', filename='foo.bar')or directly link to your files with http://example.com/static/foo.bar.

基本上,您只需要在包的根目录下有一个“静态”文件夹,然后您就可以使用http://example.com/static/foo.bar使用url_for('static', filename='foo.bar')或直接链接到您的文件。

EDIT: As suggested in the comments you could directly use the '/static/foo.bar'URL path BUTurl_for()overhead (performance wise) is quite low, and using it means that you'll be able to easily customise the behaviour afterwards (change the folder, change the URL path, move your static files to S3, etc).

编辑:正如评论中所建议的,您可以直接使用'/static/foo.bar'URL 路径,url_for()开销(性能方面)非常低,使用它意味着您之后可以轻松自定义行为(更改文件夹,更改 URL 路径,将您的静态文件移动到 S3 等)。

回答by Kyle Sum

What I use (and it's been working great) is a "templates" directory and a "static" directory. I place all my .html files/Flask templates inside the templates directory, and static contains CSS/JS. render_template works fine for generic html files to my knowledge, regardless of the extent at which you used Flask's templating syntax. Below is a sample call in my views.py file.

我使用的(并且一直运行良好)是一个“模板”目录和一个“静态”目录。我将所有 .html 文件/Flask 模板放在模板目录中,静态包含 CSS/JS。据我所知,无论您在多大程度上使用 Flask 的模板语法,render_template 都适用于通用 html 文件。下面是我的 views.py 文件中的一个示例调用。

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

Just make sure you use url_for() when you do want to reference some static file in the separate static directory. You'll probably end up doing this anyways in your CSS/JS file links in html. For instance...

当您确实想引用单独的静态目录中的某些静态文件时,请确保使用 url_for() 。无论如何,您最终可能会在 html 中的 CSS/JS 文件链接中执行此操作。例如...

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

Here's a link to the "canonical" informal Flask tutorial - lots of great tips in here to help you hit the ground running.

这是“规范的”非正式 Flask 教程的链接 - 这里有很多很棒的技巧可以帮助您开始工作。

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

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

回答by Harvey

   By default, flask use a "templates" folder to contain all your template files(any plain-text file, but usually .htmlor some kind of template language such as jinja2 ) & a "static" folder to contain all your static files(i.e. .js.cssand your images).
   In your routes, u can use render_template()to render a template file (as I say above, by default it is placed in the templatesfolder) as the response for your request. And in the template file (it's usually a .html-like file), u may use some .jsand/or `.css' files, so I guess your question is how u link these static files to the current template file.

   默认情况下,flask 使用“模板”文件夹来包含所有模板文件(任何纯文本文件,但通常.html或某种模板语言,例如 jinja2 )和“静态”文件夹来包含所有静态文件(即.js.css和你的图像)。
   在你的routes, 你可以render_template()用来渲染一个模板文件(正如我上面所说,默认情况下它被放置在templates文件夹中)作为对你的请求的响应。在模板文件(通常是 .html 类文件)中,您可能会使用一些.js和/或“.css”文件,所以我猜您的问题是您如何将这些静态文件链接到当前模板文件。

回答by EpicPandaForce

A simplest working example based on the other answers is the following:

基于其他答案的最简单的工作示例如下:

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)

With the HTML called index.html:

使用名为index.html的 HTML :

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

IMPORTANT:And index.htmlis in a folder called static, meaning <projectpath>has the .pyfile, and <projectpath>\statichas the htmlfile.

重要提示:index.html的是一个文件夹,名为静态的,这意味着<projectpath>.py文件,<projectpath>\statichtml文件。

If you want the server to be visible on the network, use app.run(debug=True, host='0.0.0.0')

如果您希望服务器在网络上可见,请使用 app.run(debug=True, host='0.0.0.0')

EDIT:For showing all files in the folder if requested, use this

编辑:如果需要显示文件夹中的所有文件,请使用此

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

Which is essentially BlackMamba's answer, so give them an upvote.

这基本上BlackMamba是 的答案,所以给他们一个赞成票。

回答by sharpshadow

You can also, and this is my favorite, set a folder as static path so that the files inside are reachable for everyone.

您也可以,这是我最喜欢的,将文件夹设置为静态路径,以便每个人都可以访问其中的文件。

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

With that set you can use the standard HTML:

使用该集合,您可以使用标准 HTML:

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

回答by user1671599

For angular+boilerplate flow which creates next folders tree:

对于创建下一个文件夹树的 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

I use following solution:

我使用以下解决方案:

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

It helps to redefine 'static' folder to custom.

它有助于将“静态”文件夹重新定义为自定义。

回答by BlackMamba

You can use this function :

您可以使用此功能:

send_static_file(filename)
Function used internally to send static files from the static folder to the browser.

send_static_file(filename)
内部使用的函数,用于将静态文件从静态文件夹发送到浏览器。

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

回答by danfromisrael

So I got things working (based on @user1671599 answer) and wanted to share it with you guys.

所以我开始工作了(基于@user1671599 的回答)并想与你们分享。

(I hope I'm doing it right since it's my first app in Python)

(我希望我做对了,因为这是我的第一个 Python 应用程序)

I did this -

我做了这个——

Project structure:

项目结构:

enter image description here

在此处输入图片说明

server.py:

服务器.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:

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)

回答by forzagreen

Use redirectand url_for

使用redirecturl_for

from flask import redirect, url_for

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

This servers all files (css & js...) referenced in your html.

这会为您的 html 中引用的所有文件(css 和 js...)提供服务。