webentwicklung-frage-antwort-db.com.de

So stellen Sie statische Dateien in Flask bereit

Das ist also peinlich. Ich habe eine Anwendung, die ich in Flask zusammengestellt habe, und derzeit wird nur eine einzige statische HTML-Seite mit Links zu CSS und JS bereitgestellt. Und ich kann nicht finden, wo in der Dokumentation Flask beschrieben wird, wie statische Dateien zurückgegeben werden. Ja, ich könnte render_template verwenden, aber ich weiß, dass die Daten nicht templatisiert sind. Ich hätte gedacht, dass send_file oder url_for das Richtige ist, aber ich konnte sie nicht zur Arbeit bringen. In der Zwischenzeit öffne ich die Dateien, lese den Inhalt und baue eine Response mit dem entsprechenden Mimetyp auf:

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 __== '__main__':  # pragma: no cover
    app.run(port=80)

Jemand möchte dafür ein Codebeispiel oder eine URL angeben? Ich weiß, dass das einfach sein wird.

355
hughdbrown

Die bevorzugte Methode ist die Verwendung von nginx oder einem anderen Webserver, um statische Dateien bereitzustellen. Sie können es effizienter als Flask tun.

Sie können jedoch auch send_from_directory verwenden, um Dateien aus einem Verzeichnis zu senden.

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 __== "__main__":
    app.run()

Verwenden Sie notsend_file oder send_static_file mit einem vom Benutzer angegebenen Pfad.

send_static_file beispiel:

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

Ich bin sicher, dass Sie dort finden, was Sie brauchen: http://flask.pocoo.org/docs/quickstart/#static-files

Im Grunde benötigen Sie nur einen "statischen" Ordner im Stammverzeichnis Ihres Pakets, und dann können Sie url_for('static', filename='foo.bar') verwenden oder direkt mit http://example.com/static/foo.bar eine Verknüpfung zu Ihren Dateien herstellen.

EDIT: Wie in den Kommentaren vorgeschlagen, können Sie direkt den '/static/foo.bar'-URL-Pfad VERWENDEN, ABERurl_for()-Overhead (in Bezug auf die Leistung) ist relativ gering, und die Verwendung bedeutet, dass Sie dies problemlos tun können Passen Sie das Verhalten anschließend an (Ändern Sie den Ordner, ändern Sie den URL-Pfad, verschieben Sie die statischen Dateien in S3 usw.).

70
b4stien

Sie können auch, und das ist mein Favorit, einen Ordner als statischen Pfad festlegen, so dass die darin enthaltenen Dateien für jeden erreichbar sind.

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

Mit diesem Set können Sie das Standard-HTML verwenden:

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

Wenn Sie nur den Speicherort Ihrer statischen Dateien verschieben möchten, können Sie die Pfade im Konstruktor am einfachsten deklarieren. Im folgenden Beispiel habe ich meine Vorlagen und statischen Dateien in einen Unterordner namens web verschoben.

app = Flask(__name__,
            static_url_path='', 
            static_folder='web/static',
            template_folder='web/templates')
  • static_url_path='' entfernt alle vorangegangenen Pfade von der URL (d. H Standardeinstellung /static).
  • static_folder='web/static' teilt Flask mit, welche Dateien unter web/static gefunden werden sollen.
  • template_folder='web/templates', in ähnlicher Weise ändert sich der Ordner __.-Vorlagen.

Bei Verwendung dieser Methode gibt die folgende URL eine CSS-Datei zurück:

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

Zum Schluss noch ein Auszug der Ordnerstruktur, wobei flask_server.py die Flask-Instanz ist:

 Nested Static Flask Folders

38
Richard Dunn

Sie können diese Funktion verwenden:

send_static_file(filename)
Funktion, die intern verwendet wird, um statische Dateien aus dem statischen Ordner an den Browser zu senden.

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

Was ich benutze (und es hat großartig funktioniert) ist ein "Vorlagen" -Verzeichnis und ein "statisches" Verzeichnis. Ich stelle alle meine .html-Dateien/Flask-Vorlagen in das Vorlagenverzeichnis und statisch enthält CSS/JS. render_template funktioniert nach meinem Wissen für generische HTML-Dateien, unabhängig davon, in welchem ​​Umfang Sie die Flask-Schablonensyntax verwendet haben. Unten finden Sie einen Beispielaufruf in meiner views.py-Datei.

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

Stellen Sie einfach sicher, dass Sie url_for () verwenden, wenn Sie auf eine statische Datei im separaten statischen Verzeichnis verweisen möchten. Sie werden dies wahrscheinlich ohnehin in Ihren CSS/JS-Dateilinks in HTML tun. Zum Beispiel...

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

Hier ist ein Link zum "kanonischen" informellen Flask-Tutorial. Hier finden Sie viele nützliche Tipps, die Ihnen dabei helfen werden, den Boden zu öffnen. 

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

33
Kyle Sum

Ein einfachstes Arbeitsbeispiel basierend auf den anderen Antworten ist das Folgende:

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

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

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

Mit dem HTML-Code namens index.html:

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

WICHTIG: Und index.html befindet sich in einem Ordner mit dem Namen static . <projectpath> hat die .py-Datei und <projectpath>\static die html-Datei.

Wenn der Server im Netzwerk sichtbar sein soll, verwenden Sie app.run(debug=True, Host='0.0.0.0')

EDIT: Verwenden Sie diese Option, um alle Dateien im Ordner anzuzeigen, wenn Sie dazu aufgefordert werden

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

Was im Wesentlichen BlackMambas Antwort ist, also geben Sie ihnen eine positive Bewertung.

31
EpicPandaForce

Für den Winkel + Boilerplate-Fluss, der den nächsten Ordnerbaum erstellt:

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

Ich verwende folgende Lösung:

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

Es ist hilfreich, den "statischen" Ordner in benutzerdefiniert zu definieren.

7
user1671599

Also habe ich die Dinge zum Laufen gebracht (basierend auf der Antwort von @ user1671599) und wollte sie mit euch teilen.

(Ich hoffe, ich mache es richtig, da es meine erste App in Python ist.)

Ich tat dies -

Projektstruktur:

enter image description here

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)
5
danfromisrael

Gedanken zum Teilen ... dieses Beispiel.

from flask import Flask
app = Flask(__name__)

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

if __== '__main__':
    app.run(Host='0.0.0.0')

Das funktioniert besser und einfacher.

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

Dieser Server enthält alle Dateien (css & js ...), auf die in Ihrer HTML-Datei verwiesen wird.

2
forzagreen

Alle Antworten sind gut, aber was für mich gut funktioniert hat, ist die einfache Funktion send_file von Flask. Dies funktioniert gut, wenn Sie nur eine HTML-Datei als Antwort senden müssen, wenn Host: port/ApiName die Ausgabe von anzeigt die Datei im Browser


@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])```

1
Binoy S Kumar

Wenn Sie nur versuchen, eine Datei zu öffnen, können Sie app.open_resource() verwenden. Das Lesen einer Datei würde ungefähr so ​​aussehen

with app.open_resource('/static/path/yourfile'):
      #code to read the file and do something
0

Eine der einfachen Möglichkeiten. Prost!

demo.py

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

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

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

Erstellen Sie nun einen Ordnernamen mit dem Namen templates . Fügen Sie Ihre index.html -Datei in templates folder hinzu.

index.html

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

Projektstruktur

-demo.py
-templates/index.html
0
Maheshvirus

Standardmäßig verwendet flask einen "Vorlagen" -Ordner für alle Ihre Vorlagendateien (alle Nur-Text-Dateien, aber normalerweise .html oder eine Art von Vorlagensprache wie "jinja2") und einen "statischen" Ordner, der alle Ihre statischen Dateien enthält (dh .js.css und Ihre Bilder). 
In Ihrer routes können Sie render_template() zum Rendern einer Vorlagendatei verwenden (wie ich oben sage, diese wird standardmäßig im Ordner templates abgelegt) als Antwort für Ihre Anfrage. Und in der Vorlagendatei (normalerweise eine .html-ähnliche Datei) können Sie einige .js- und/oder `.css'-Dateien verwenden. Ich denke, Ihre Frage ist, wie Sie diese statischen Dateien mit der aktuellen Vorlagendatei verknüpfen. 

0
Harvey