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

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

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.


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:

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.


@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


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

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.


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.


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.


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)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.