플라스크에서 정적 파일을 제공하는 방법


539

그래서 이것은 창피합니다. 나는 함께 던진 응용 프로그램을 가지고 있으며 Flask현재 CSS와 JS에 대한 링크가있는 단일 정적 HTML 페이지를 제공하고 있습니다. 그리고 문서에서 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)

누군가 코드 샘플이나 URL을 제공하고 싶습니까? 나는 이것이 간단하게 죽을 것이라는 것을 안다.


6
정적 파일을 제공하기 위해 nginx 또는 다른 웹 서버를 사용하지 않는 이유
atupal

8
실제로 파일을 "서비스하는"방법은 프로덕션 (웹 서버)과 개발 (로컬 컴퓨터 또는 다른 테스트 영역)과 다를 수 있습니다. 일부 답변이 지적했듯이 플라스크를 사용하여 정적 파일을 제공하지 않고 대신 자신의 디렉토리에 저장 한 다음 실제 웹 서버 (Apache, nginx 등)에서 해당 파일을 직접 서버에 보관하십시오.
Mark Hildreth


75
"nginx를 사용하지 않는 이유는…"랩탑의 개발자 모드에서 실행할 때는 한 가지만, 한 가지만 실행하는 것이 좋습니다. 그렇습니다. 그것은 약간 다른 일이지만, 괜찮습니다.
Thanatos

1
프로덕션 환경에서도 캐시 레이어 (예 : Varnish 또는 Nginx 또는 CDN)를 사용하여이를 보는 것이 매우 일반적입니다.
토마스 데코

답변:


642

선호되는 방법은 nginx 또는 다른 웹 서버를 사용하여 정적 파일을 제공하는 것입니다. 그들은 플라스크보다 더 효율적으로 할 수 있습니다.

그러나 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_file하거나 send_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 지원 : return app.send_static_file (os.path.join ( 'js', path) .replace ( '\\', '/'))
Tony BenBrahim

9
침입자가이 방법을 이용하여 / js / < "../ yourflaskapp.py">의 영리한 인코딩을 찾아서 플라스크 소스 파일을 탐색 할 수 있습니까?
akiva

30
@kiwi send_from_directory는 보안 문제를 해결하도록 설계되었습니다. 경로가 특정 디렉토리 외부로 연결되면 오류가 발생합니다.
jpmc26

10
"send_file 또는 send_static_file을 사용자 제공 경로와 함께 사용하지 마십시오." 왜 안돼?
Drew Verlee

6
@DenisV 그것은 파이썬과 관련이 없으며 URL 매개 변수를 정의하기위한 Flask 규칙입니다 ( http://flask.pocoo.org/docs/0.12/api/#url-route-registrations 참조 ). 간단히 말해서 <path>동일합니다 <string:path>, 당신은 플라스크가 확인 원하기 때문에 경로를 같은 매개 변수는 요청 <path:path>.
b4stien

135

정적 파일의 위치를 ​​이동하려는 경우 가장 간단한 방법은 생성자에서 경로를 선언하는 것입니다. 아래 예에서 템플릿과 정적 파일을이라는 하위 폴더로 옮겼습니다 web.

app = Flask(__name__,
            static_url_path='', 
            static_folder='web/static',
            template_folder='web/templates')
  • static_url_path=''URL에서 선행 경로를 제거합니다 (예 : default /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.pyFlask 인스턴스가있는 폴더 구조를 살펴 보겠습니다.

중첩 된 정적 플라스크 폴더


9
이것이 나를 위해 일한 것입니다. Send_from_directory는 모든 권장 사항에도 불구하고 작동하지 않았습니다.
GA

완벽하게 작동합니다. 너무 감사합니다 <3.
Thuat Nguyen

경로는 어떻게 생겼습니까? get_static_file('index.html')?
배트맨

GA가 말했듯이 이것은 나에게 효과가 없었으며 모든 것을 고쳤습니다. 많은 감사
안드레이 Starenky

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 2016 년

78

나는 당신이 거기에 필요한 것을 찾을 것이라고 확신합니다 : http://flask.pocoo.org/docs/quickstart/#static-files

기본적으로 패키지 루트에 "static"폴더 만 있으면 http://example.com/static/foo.barurl_for('static', filename='foo.bar') 를 사용하여 파일을 직접 사용 하거나 파일에 연결할 수 있습니다 . .

편집 : 의견에서 제안한 것처럼 '/static/foo.bar'URL 경로를 직접 사용할 수 있지만 url_for() 오버 헤드 (성능 현명한)는 매우 낮으므로 나중에 동작을 쉽게 사용자 정의 할 수 있습니다 (폴더 변경, URL 경로 변경, 정적 파일을 S3 등으로 이동하십시오.


14
'/static/foo.bar'직접 하지 않습니까?
Tyler Long

3
@TylerLong이 맞습니다-정적 디렉토리에 이미 저장된 파일에 링크하려면 경로 코드없이 직접 링크 할 수 있습니다.
hamx0r

42

이 기능을 사용할 수 있습니다 :

send_static_file(filename)
정적 파일을 정적 폴더에서 브라우저로 보내는 데 내부적으로 사용되는 기능입니다.

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

1
이것은 큰 두통없이 나를 위해 일한 유일한 사람이었습니다.
Kenny Powers

같은. Flash가 다른 곳에서 HTML을 제작하는 RIA가 아닌 템플릿 시스템을 사용한다는 아이디어에 크게 의존하고 있습니다.
NiKo

15
경고 : 이것은 send_static_file사용자 입력 으로 전화를 걸 때 큰 보안 문제 입니다. 이 솔루션을 중요한 용도로 사용하지 마십시오.
xApple

41

내가 사용하고 잘 작동하는 것은 "템플릿"디렉토리와 "정적"디렉토리입니다. 모든 .html 파일 / Flask 템플릿을 templates 디렉토리 안에 넣고 static에는 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.htmlstatic 이라는 폴더 에 있습니다. 즉 <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답이므로 공감하십시오.


중요한 관찰 감사합니다!
Gleidson Cardoso da Silva

13

다음 폴더 트리를 작성하는 각도 + 보일러 플레이트 흐름의 경우 :

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의 통지 내가 basicly 같은 인 'add_url_rule'intead '경로'사용
danfromisrael

7

그래서 (@ user1671599 답변을 기반으로) 작동하는 것들을 얻었고 여러분과 공유하고 싶었습니다.

(파이썬에서 처음으로 앱이기 때문에 제대로하고 싶습니다.)

나는 이걸했다 -

프로젝트 구조 :

여기에 이미지 설명을 입력하십시오

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

간단한 방법 중 하나입니다. 건배!

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해결책 을 알고 있다고 말 했지만 파일을 대체하지 않고 정적 파일이기 때문에 해결하고 싶지 않았다.
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

사용 redirecturl_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 )을 포함하는 파일이 동일한 위치에 있으면 app = Flask ( name )을 배치 해도됩니다.이 파일이 다른 위치에 있으면 활성화 할 템플릿 위치를 지정해야합니다 위치를 가리키는 플라스크


4
이것이 왜 효과가 있는지 설명해 줄 수 있습니까?
경제

1
설명을 제공하는 이 답변 과 어떻게 다릅니 까?
Gino Mempin

내 답변 @economy
Novak254에

1

모든 대답은 훌륭하지만 나에게 잘 맞는 것은 send_fileFlask 의 간단한 기능 을 사용하는 것 입니다. 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과 같은 파일)에서 u는 일부 .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.