Arquivos estáticos no Flask - robots.txt, sitemap.xml (mod_wsgi)

94

Existe alguma solução inteligente para armazenar arquivos estáticos no diretório raiz do aplicativo Flask. Espera-se que o arquivo robots.txt e o sitemap.xml sejam encontrados em /, então minha ideia era criar rotas para eles:

@app.route('/sitemap.xml', methods=['GET'])
def sitemap():
  response = make_response(open('sitemap.xml').read())
  response.headers["Content-type"] = "text/plain"
  return response

Deve haver algo mais conveniente :)

biesia
fonte

Respostas:

78

A melhor maneira é definir static_url_path para root url

from flask import Flask

app = Flask(__name__, static_folder='static', static_url_path='')
dns
fonte
Vale ressaltar que a static_folder não precisa estar na pasta do projeto. por exemplo, static_folder = '/ app / ui' está bem.
ashic
66

@vonPetrushev está certo, na produção você vai querer servir arquivos estáticos via nginx ou apache, mas para o desenvolvimento é bom ter seu ambiente de desenvolvimento simples, tendo seu aplicativo Python servindo o conteúdo estático também, então você não precisa se preocupar sobre como alterar configurações e vários projetos. Para fazer isso, você vai querer usar o SharedDataMiddleware .

from flask import Flask
app = Flask(__name__)
'''
Your app setup and code
'''
if app.config['DEBUG']:
    from werkzeug import SharedDataMiddleware
    import os
    app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {
      '/': os.path.join(os.path.dirname(__file__), 'static')
    })

Este exemplo assume que seus arquivos estáticos estão na pasta "estáticos", ajuste para o que for adequado ao seu ambiente.

Philip Southam
fonte
1
OBRIGADO! Isso é o que eu precisava! Estou procurando fazer isso para o meu heroku de produção. Veja as respostas no seguinte tópico: flask.pocoo.org/mailinglist/archive/2012/2/22/…
David
2
Atenção - há uma maneira mais fácil de lidar com isso agora. Verifique minha resposta.
Sean McSomething
1
Existe uma maneira de o SharedDataMiddleware resolver apenas '/' para index.html ou algo semelhante?
gromgull de
63

A resposta mais limpa a esta pergunta é a resposta a esta pergunta (idêntica) :

from flask import Flask, request, send_from_directory
app = Flask(__name__, static_folder='static')    

@app.route('/robots.txt')
@app.route('/sitemap.xml')
def static_from_root():
    return send_from_directory(app.static_folder, request.path[1:])

Para resumir:

  • como David apontou, com a configuração certa, está tudo bem servir alguns arquivos estáticos através do prod
  • procurar /robots.txt não deve resultar em um redirecionamento para /static/robots.txt. (Na resposta de Seans, não está imediatamente claro como isso é alcançado.)
  • não é limpo adicionar arquivos estáticos à pasta raiz do aplicativo
  • finalmente, a solução proposta parece muito mais limpa do que adicionar abordagem de middleware:
bebbi
fonte
22

Mesmo que esta seja uma velha pergunta respondida, estou respondendo porque esta postagem aparece bem no topo dos resultados do Google. Embora não seja abordado na documentação, se você ler os documentos da API para o construtor de objeto Flask Application, será abordado. Passando o parâmetro nomeado static_folderassim:

from flask import Flask
app = Flask(__name__,
            static_folder="/path/to/static",
            template_folder="/path/to/templates")

... você pode definir de onde os arquivos estáticos são servidos. Da mesma forma, você pode definir um template_folder, o seu nome static_url_path.

Sean McSomething
fonte
@chmike sim, o padrão é, /staticmas você pode alterar isso substituindo static_url_path.
Sean McSomething de
Isso está correto, mas outras respostas são mais flexíveis. Este é limitado pelo fato de que só pode servir a um caminho de diretório.
Thomas Dignan
Esta não é a resposta à pergunta original.
Paolo Casciello de
2
Se você definir static_url_path para "", poderá servir arquivos de /.
Beau
Isso força o Flask a servir arquivos estáticos. E se você quiser que o nginx ou o apache os sirva?
Markon de
15

A entrega de arquivos estáticos não tem nada a ver com o aplicativo destinado a entregar conteúdo dinâmico. A maneira correta de servir arquivos estáticos depende de qual servidor você está usando. Afinal, quando você colocar seu aplicativo em funcionamento, precisará vinculá-lo a um servidor web. Posso falar apenas em apache httpd, então a forma de servir arquivos estáticos é definida no host virtual que você está vinculando ao seu aplicativo por meio de mod-wsgi. Aqui está o guia que mostrará como veicular mapas de sites, robots.txt ou qualquer conteúdo estático: http://code.google.com/p/modwsgi/wiki/QuickConfigurationGuide#Mounting_At_Root_Of_Site

vonPetrushev
fonte
Essa é a resposta que estou procurando. Obrigado!
biesiad de
1
Um aplicativo destina-se a fornecer conteúdo, alguns dinâmicos e outros estáticos.
Dem Pilafian
14

Outra maneira de enviar arquivos estáticos é usar uma regra pega-tudo como esta:

@app.route('/<path:path>')
def catch_all(path):
    if not app.debug:
        flask.abort(404)
    try:
        f = open(path)
    except IOError, e:
        flask.abort(404)
        return
    return f.read()

Eu uso isso para tentar minimizar a configuração durante o desenvolvimento. Tive a ideia em http://flask.pocoo.org/snippets/57/

Além disso, estou desenvolvendo usando flask em minha máquina autônoma, mas implantando com Apache no servidor de produção. Eu uso:

file_suffix_to_mimetype = {
    '.css': 'text/css',
    '.jpg': 'image/jpeg',
    '.html': 'text/html',
    '.ico': 'image/x-icon',
    '.png': 'image/png',
    '.js': 'application/javascript'
}
def static_file(path):
    try:
        f = open(path)
    except IOError, e:
        flask.abort(404)
        return
    root, ext = os.path.splitext(path)
    if ext in file_suffix_to_mimetype:
        return flask.Response(f.read(), mimetype=file_suffix_to_mimetype[ext])
    return f.read()

[...]

if __name__ == '__main__':
    parser = optparse.OptionParser()
    parser.add_option('-d', '--debug', dest='debug', default=False,
                      help='turn on Flask debugging', action='store_true')

    options, args = parser.parse_args()

    if options.debug:
        app.debug = True
        # set up flask to serve static content
        app.add_url_rule('/<path:path>', 'static_file', static_file)
    app.run()
Ben Golding
fonte
1
Atenção - há uma maneira mais fácil de lidar com isso agora. Verifique minha resposta.
Sean McSomething
Excelente maneira se você precisa atender a vários caminhos!
Thomas Dignan
6

Isso pode ter sido adicionado desde que esta pergunta foi feita, mas eu estava procurando no "helpers.py" do flask e encontrei flask.send_from_directory:

send_from_directory(directory, filename, **options)
'''
  send_from_directory(directory, filename, **options)
  Send a file from a given directory with send_file.  This
  is a secure way to quickly expose static files from an upload folder
  or something similar.
'''

... que faz referência a flask.send_file:

send_file(filename_or_fp, mimetype=None, as_attachment=False, attachment_filename=None, add_etags=True, cache_timeout=43200, conditional=False)

... o que parece melhor para mais controle, embora send_from_directory passe ** opções diretamente para send_file.

blast_hardcheese
fonte
3

Da documentação aqui: http://flask.pocoo.org/docs/quickstart/#static-files

Os aplicativos da Web dinâmicos também precisam de arquivos estáticos. Normalmente é daí que vêm os arquivos CSS e JavaScript. Idealmente, seu servidor web está configurado para atendê-los para você, mas durante o desenvolvimento o Flask pode fazer isso também. Basta criar uma pasta chamada static em seu pacote ou ao lado de seu módulo e ela estará disponível em / static na aplicação.

Para gerar URLs para essa parte do URL, use o nome especial de URL 'estático':

url_for ('estático', nome do arquivo = 'estilo.css')

O arquivo deve ser armazenado no sistema de arquivos como static / style.css.

Josh Klein
fonte
0

Estou tendo o mesmo dilema também. Fiz alguma pesquisa e encontrei minha resposta (MHO):

Pode muito bem citar a documentação

Os aplicativos da Web dinâmicos também precisam de arquivos estáticos. Normalmente é daí que vêm os arquivos CSS e JavaScript. Idealmente, seu servidor web está configurado para atendê-los para você, mas durante o desenvolvimento o Flask pode fazer isso também . Basta criar uma pasta chamada static em seu pacote ou ao lado de seu módulo e ela estará disponível em / static na aplicação.

IMHO: Quando seu aplicativo está em produção , o serviço de arquivos estáticos deve ser (ou é idealmente) configurado no servidor da web (nginx, apache); mas durante o desenvolvimento , o Flask o disponibilizou para servir arquivos estáticos. Isso é para ajudá-lo a desenvolver-se rapidamente - sem necessidade de configurar servidores da Web e outros.

Espero que ajude.

jpanganiban
fonte
0

Experimente isto:

@app.route("/ProtectedFolder/<path:filename>")
@CheckUserSecurityAccessConditions
def Protect_Content(filename):
  return send_from_directory((os.path.join(os.path.dirname(__file__), 'ProtectedFolder')),filename)
Farzad Amirjavid
fonte