फ्लास्क में स्थिर फ़ाइलों की सेवा कैसे करें


539

तो यह शर्मनाक है। मुझे एक आवेदन मिला है जिसे मैंने एक साथ फेंक दिया है Flaskऔर अभी के लिए यह सीएसएस और जेएस के कुछ लिंक के साथ एक ही स्थिर 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, इत्यादि) को उन फाइलों को सीधे सर्वर पर भेज दें।
मार्क हिल्ड्रेथ


75
"नग्नेक्स का उपयोग क्यों नहीं किया जाता ..." क्योंकि जब मैं इसे अपने लैपटॉप पर डेवलपर मोड में चला रहा हूं, तो केवल एक चीज चलाने की जरूरत है, और केवल एक चीज। हां, यह चीजों को एक अलग बनाता है, लेकिन यह ठीक है।
थानाटोस

1
यहां तक ​​कि उत्पादन में, यह बहुत आम है, निश्चित रूप से सामने एक कैश लेयर (जैसे वार्निश या नग्नेक्स या सीडीएन) के साथ।
थॉमस डेकाक्स

जवाबों:


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
विंडोज का समर्थन करने के लिए: वापसी app.send_static_file (os.path.join ('js, path) .replace (' \\ ',' / '))
टोनी बेनब्राहिम

9
क्या कोई हमलावर इस प्रकार का शोषण कर सकता है कि फ्लास्क स्रोत फ़ाइलों को ब्राउज़ करने के लिए "/ .. yourflaskapp.py"> के कुछ चतुर एन्कोडिंग ब्राउज़ करके?
अकीवा

30
@kiwi send_from_directoryको उस सुरक्षा समस्या को हल करने के लिए डिज़ाइन किया गया है। यदि पथ विशेष निर्देशिका से बाहर की ओर जाता है, तो यह त्रुटि के लिए मौजूद है।
jpmc26

10
"उपयोगकर्ता-प्रदत्त पथ के साथ send_file या send_static_file का उपयोग न करें।" क्यों नहीं?
ड्रू वर्ली

6
@DenisV का पाइथन-से से कोई लेना-देना नहीं है, यह URL मापदंडों को परिभाषित करने के लिए फ्लास्क सम्मेलन है (देखें http://flask.pocoo.org/docs/0.12/api/#url-route-regments )। संक्षेप <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 (यानी डिफ़ॉल्ट /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फ्लास्क उदाहरण है:

नेस्टेड स्टेटिक फ्लास्क फोल्डर्स


9
मेरे लिए भी यही काम किया। Send_from_directory सिर्फ इसके लिए सभी सिफारिशों के बावजूद काम नहीं किया।
जीए

सही काम करता है। बहुत बहुत धन्यवाद <३।
थुगट गुयेन

रास्ता कैसा दिखता है? get_static_file('index.html')?
बैटमैन

यह अच्छी तरह से काम करता है, जैसे जीए ने कहा, मेरे लिए कुछ और काम नहीं किया और यह सब तय किया। बहुत सराहना की
एंड्री स्टारकेनी

81

आप भी कर सकते हैं, और यह मेरा पसंदीदा है, एक फ़ोल्डर को स्थिर पथ के रूप में सेट करें ताकि अंदर की फाइलें सभी के लिए उपलब्ध हो सकें।

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

उस सेट के साथ आप मानक HTML का उपयोग कर सकते हैं:

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

4
अगर फ़ाइल project/static/style.cssउपलब्ध है तो अच्छी तरह से काम करता है।
पावेल वलसोव

6
लाइन "ऐप = फ्लास्क (....)" की जरूरत है "static_folder" भी एक पैरामीटर होने के लिए
datdinhquoc

मैं इस मुद्दे से घंटों जूझ रहा हूँ! मुझे केवल एक ही तर्क याद आ रहा था!
LogicalBranch

78

मुझे यकीन है कि आपको वह मिलेगा जो आपको चाहिए: http://flask.pocoo.org/docs/quickstart/#static-files

मूल रूप से आपको बस अपने पैकेज के मूल में एक "स्थिर" फ़ोल्डर की आवश्यकता होती है, और फिर आप url_for('static', filename='foo.bar')अपनी फ़ाइलों के साथ सीधे या सीधे लिंक का उपयोग कर सकते हैं http://example.com/static/foo.bar के

संपादित करें : जैसा कि टिप्पणियों में सुझाया गया है आप सीधे '/static/foo.bar'URL पथ का उपयोग कर सकते हैं BUT url_for() ओवरहेड (प्रदर्शन वार) काफी कम है, और इसका उपयोग करने का मतलब है कि आप बाद में आसानी से व्यवहार को अनुकूलित करने में सक्षम होंगे (फ़ोल्डर को बदलें, URL पथ को बदलें,) अपनी स्थैतिक फ़ाइलों को S3, आदि में स्थानांतरित करें)।


14
'/static/foo.bar'सीधे क्यों नहीं ?
टायलर लॉन्ग

3
@ टायलरलॉन्ग सही है - यदि आप किसी ऐसी फाइल से लिंक करना चाहते हैं जो पहले से ही आपके स्टैटिक डायरेक्टरी में सेव है, तो आप बिना किसी रूट कोड के सीधे उससे लिंक कर सकते हैं।
हैमएक्स 0 आरआर 23'14

42

आप इस फ़ंक्शन का उपयोग कर सकते हैं:

send_static_file(filename)
स्टैटिक फोल्डर से ब्राउजर में स्टैटिक फाइल भेजने के लिए फंक्शन का आंतरिक रूप से उपयोग किया जाता है।

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

1
यह एकमात्र ऐसा था जिसने बड़े सिरदर्द के बिना मेरे लिए काम किया।
केनी पॉवर्स

वही। जहां मुझे एहसास हुआ कि फ्लैश इस विचार पर निर्भर करता है कि हम उनके टेम्पलेट सिस्टम का उपयोग करने जा रहे हैं, न कि कुछ आरआईए जहां एचटीएमएल का उत्पादन कहीं और किया जाता है।
नीको

15
चेतावनी: send_static_fileउपयोगकर्ता इनपुट के साथ कॉल करने के लिए यह एक बड़ी सुरक्षा चिंता है । महत्वपूर्ण कुछ भी इस समाधान का उपयोग न करें।
xApple

41

मैं जो उपयोग करता हूं (और यह बहुत अच्छा काम कर रहा है) एक "टेम्पलेट" निर्देशिका और एक "स्थिर" निर्देशिका है। मैं अपनी सभी .html फाइलें / फ्लास्क टेम्प्लेट्स को टेम्प्लेट डायरेक्टरी के अंदर रखता हूं, और स्थैतिक में CSS / JS शामिल हैं। रेंडर_template मेरे ज्ञान के लिए सामान्य HTML फ़ाइलों के लिए ठीक काम करता है, चाहे आप उस स्तर की परवाह किए बिना जहां आपने फ्लास्क के टेम्पलेटिंग सिंटैक्स का उपयोग किया हो। नीचे मेरे विचार फ़ाइल में एक नमूना कॉल है।

@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>

यहां "कैनोनिकल" अनौपचारिक फ्लास्क ट्यूटोरियल का लिंक दिया गया है - जमीन पर चलने में मदद करने के लिए बहुत सारे शानदार सुझाव।

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)

HTML के साथ index.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

कोणीय + बॉयलरप्लेट प्रवाह के लिए जो अगले फ़ोल्डर ट्री बनाता है:

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' इंटीड 'मार्ग का उपयोग किया है जो मूल रूप से एक ही है
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 (जो आपको
गितुब

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)

अब फोल्डर का नाम बनाएं जिसका नाम टेम्प्लेट हैटेम्प्लेट फ़ोल्डर के अंदर अपनी 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समाधान के बारे में जानता था, लेकिन ऐसा नहीं करना चाहता था क्योंकि फ़ाइल बिना किसी प्रतिस्थापन के स्थिर थी: "हाँ, मैं रेंडर_टैमप्लेट का उपयोग कर सकता था, लेकिन मुझे पता है कि डेटा को अस्थायी नहीं किया गया है।"
हुग्डब्रोर्न

एकमात्र समाधान जो विंडोज में आसानी से काम करता था, धन्यवाद!
बसज

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

यह बेहतर और सरल काम करता है।


क्या आप विस्तार से बता सकते हैं कि यह कैसे बेहतर होगा?
अर्शो

1
lmao हर दूसरी विधि ने मुझे कुछ कष्टप्रद फ़ाइल दीं जिसमें त्रुटियां नहीं मिलीं। अच्छा 1 जीवन
दिमित्री डीबी

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>

एचटीएमएल

{% 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")

यदि आपके रूट डायरेक्टरी में टेम्प्लेट हैं, तो ऐप = फ्लास्क ( नाम ) को रखने से काम चलेगा यदि इसमें जो फ़ाइल है वह भी उसी स्थान पर है, यदि यह फ़ाइल किसी अन्य स्थान पर है, तो आपको सक्षम करने के लिए टेम्पलेट स्थान निर्दिष्ट करना होगा। स्थान पर इंगित करने के लिए फ्लास्क


4
क्या आप कुछ स्पष्टीकरण प्रदान कर सकते हैं कि यह क्यों काम करता है?
इकोनॉमी

1
यह इस उत्तर से अलग कैसे है जो स्पष्टीकरण प्रदान करता है?
गीनो मेम्पिन

मैंने अपने उत्तर @economy
Novak254

1

सभी उत्तर अच्छे हैं, लेकिन मेरे लिए जो अच्छा काम किया है वह सिर्फ send_fileफ्लास्क के सरल कार्य का उपयोग कर रहा है । यह तब अच्छी तरह से काम करता है जब आपको होस्ट के रूप में प्रतिक्रिया के रूप में केवल एक html फ़ाइल भेजने की आवश्यकता होती है : पोर्ट / ApiName ब्राउज़र में फ़ाइल का आउटपुट दिखाएगा


@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उपयोग कर सकते हैं 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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.