[英]How to serve static files in Flask
所以这很尴尬。 我在Flask
中有一个应用程序,现在它只提供一个 static HTML 页面,其中包含一些指向 CSS 和 JS 的链接。 而且我找不到文档Flask
中描述返回 static 文件的位置。 是的,我可以使用render_template
但我知道数据没有模板化。 我原以为send_file
或url_for
是正确的,但我无法让它们工作。 与此同时,我正在打开文件、阅读内容并使用适当的 mimetype 设置Response
:
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 吗? 我知道这将非常简单。
在生产环境中,在您的应用程序前面配置 HTTP 服务器(Nginx、Apache 等),以便为来自静态文件夹的/static
请求提供服务。 专用的 Web 服务器非常擅长高效地提供静态文件,尽管您可能不会注意到与 Flask 在低容量下的区别。
Flask 会自动创建一个/static/<path:filename>
路由,该路由将在定义 Flask 应用程序的 Python 模块旁边的static
文件夹下提供任何filename
。 使用url_for
链接到静态文件: url_for('static', filename='js/analytics.js')
您还可以使用send_from_directory
从您自己的路由中的目录提供文件。 这需要一个基本目录和一个路径,并确保路径包含在目录中,这样可以安全地接受用户提供的路径。 这在您想在提供文件之前检查某些内容的情况下很有用,例如登录用户是否具有权限。
from flask import send_from_directory
@app.route('/reports/<path:path>')
def send_report(path):
return send_from_directory('reports', path)
不要将send_file
或send_static_file
与用户提供的路径一起使用。 这将使您面临目录遍历攻击。 send_from_directory
旨在安全地处理已知目录下的用户提供的路径,如果路径试图转义该目录,则会引发错误。
如果您在内存中生成文件而不将其写入文件系统,则可以将BytesIO
对象传递给send_file
以像文件一样提供它。 在这种情况下,您需要将其他参数传递给send_file
,因为它无法推断文件名或内容类型等内容。
如果您只想移动静态文件的位置,那么最简单的方法是在构造函数中声明路径。 在下面的示例中,我已将模板和静态文件移动到名为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 实例:
您也可以,这是我最喜欢的,将文件夹设置为静态路径,以便每个人都可以访问其中的文件。
app = Flask(__name__, static_url_path='/static')
使用该集合,您可以使用标准 HTML:
<link rel="stylesheet" type="text/css" href="/static/style.css">
我相信你会在那里找到你需要的东西:http: //flask.pocoo.org/docs/quickstart/#static-files
基本上你只需要在你的包的根目录有一个“静态”文件夹,然后你可以使用url_for('static', filename='foo.bar')
或者直接使用http://example.com/链接到你的文件静态/foo.bar 。
编辑:正如评论中所建议的,您可以直接使用'/static/foo.bar'
路径,但url_for()
开销(性能方面)非常低,使用它意味着您可以轻松自定义行为之后(更改文件夹、更改 URL 路径、将静态文件移动到 S3 等)。
您可以使用此功能:
send_static_file(filename)
内部用于将静态文件从静态文件夹发送到浏览器的函数。
app = Flask(__name__)
@app.route('/<path:path>')
def static_file(path):
return app.send_static_file(path)
我使用的(而且效果很好)是一个“模板”目录和一个“静态”目录。 我将所有 .html 文件/Flask 模板放在模板目录中,静态包含 CSS/JS。 据我所知,无论您在多大程度上使用 Flask 的模板语法,render_template 都适用于通用 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
基于其他答案的最简单的工作示例如下:
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位于名为static的文件夹中,这意味着<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
的答案,所以给他们一个赞成票。
对于创建下一个文件夹树的 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')
...
它有助于将“静态”文件夹重新定义为自定义。
app = Flask(__name__, static_folder="your path to static")
如果您的根目录中有模板,如果包含此文件的文件也位于同一位置,则放置 app=Flask( name ) 将起作用,如果此文件位于另一个位置,则必须指定模板位置才能启用Flask 指向位置
默认情况下,名为“static”的文件夹包含所有静态文件这是代码示例:
<link href="{{ url_for('static', filename='vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">
所以我得到了工作(基于@user1671599 的回答)并想与你们分享。
(我希望我做对了,因为它是我在 Python 中的第一个应用程序)
我这样做了-
项目结构:
服务器.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)
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 ...)提供服务。
一种简单的方法。 干杯!
演示.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文件
索引.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
想到分享....这个例子。
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')
这工作得更好更简单。
我遇到的问题与使用static_url_path
和static_folder
时没有为目录服务的index.html
文件有关。
这是我的解决方案:
import os
from flask import Flask, send_from_directory
from flask.helpers import safe_join
app = Flask(__name__)
static = safe_join(os.path.dirname(__file__), 'static')
@app.route('/')
def _home():
return send_from_directory(static, 'index.html')
@app.route('/<path:path>')
def _static(path):
if os.path.isdir(safe_join(static, path)):
path = os.path.join(path, 'index.html')
return send_from_directory(static, path)
所有的答案都很好,但对我来说效果很好的只是使用来自 Flask 的简单函数send_file
。 当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])```
最简单的方法是在主项目文件夹中创建一个静态文件夹。 包含 .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 %}
可以使用静态端点创建静态文件的 URL,如下所示:
url_for('static', filename = 'name_of_file')
<link rel="stylesheet" href="{{url_for('static', filename='borders.css')}}" />
您可以使用 Jinja 模板引擎做到这一点。
<link rel="stylesheet" href="{{url_for('static', filename='style.css')}}">
<script type="text/javascript" src="{{url_for('static', filename='script.js')}}">
默认情况下,flask 使用“模板”文件夹来包含所有模板文件(任何纯文本文件,但通常是.html
或某种模板语言,例如 jinja2 )和一个“静态”文件夹来包含所有静态文件(即.js
.css
和你的图片)。
在您的routes
中,您可以使用render_template()
来呈现模板文件(正如我上面所说,默认情况下它放置在templates
文件夹中)作为您请求的响应。 在模板文件(它通常是一个类似 .html 的文件)中,你可能会使用一些.js
和/或 `.css' 文件,所以我想你的问题是你如何将这些静态文件链接到当前的模板文件。
如果你只是想打开一个文件,你可以使用app.open_resource()
。 所以读取文件看起来像
with app.open_resource('/static/path/yourfile'):
#code to read the file and do something
在静态目录中,在该目录中创建模板目录添加所有 html 文件为 css 和 javascript 创建单独的目录,因为flask 将处理或识别模板目录中的所有 html 文件。
static -
|_ templates
|_ css
|_javascript
|_images
这对我有用:
import os
from flask import Flask, render_template, send_from_directory
app = Flask(__name__)
root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "whereyourfilesare")
@app.route('/', methods=['GET'])
def main(request):
path = request.path
if (path == '/'):
return send_from_directory(root, 'index.html')
else:
return send_from_directory(root, path[1:])
在我的情况下,我需要用户可以访问静态文件夹中的所有文件,并且我需要为我的一些 html 文件使用模板,以便可以将常见的 html 代码放在模板中并重用代码. 以下是我如何一起实现它们:
from flask import Flask, request, render_template
from flask.json import JSONEncoder
app = Flask(__name__, template_folder='static')
@app.route('/<path:path>')
def serve_static_file(path):
# In my case, only html files are having the template code inside them, like include.
if path.endswith('.html'):
return render_template(path)
# Serve all other files from the static folder directly.
return app.send_static_file(path)
我所有的文件都保存在静态文件夹下,与主烧瓶文件平行。
例如,要返回我使用过的 Adsense 文件:
@app.route('/ads.txt')
def send_adstxt():
return send_from_directory(app.static_folder, 'ads.txt')
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.