Como servir arquivos estáticos

Django, por si só, não serve arquivos estáticos (media), como imagens, folhas de estilo (CSS), ou vídeo. Esse trabalho é deixado para o servidor Web de sua escolha.

O motivo para isso é que servidores Web comuns, como Apache e lighttpd e Cherokee, são muito mais apropriados para servir arquivos estáticos do que um framework de aplicações web.

Dito isso, Django suporta arquivos estáticos durante o desenvolvimento. Você pode usar a view django.views.static.serve() para servir arquivos estáticos.

See also

Se você precisa servir mídia administrativa de uma localização não padrão, veja o parâmetro --adminmedia para runserver.

Não diga que não avisamos

Usar este método é ineficiente e inseguro. Não use isso em um ambiente de produçao. Use apenas para desenvolvimento.

Para informações sobre servir arquivos estáticos em um ambiente de produção com Apache, veja a documentação Django mod_python.

Como proceder

Aqui temos a definição formal da view serve():

def serve(request, path, document_root, show_indexes=False):

Para usá-la, somente coloque isto na sua URLconf:

(r'^site_media/(?P<path>.*)$', 'django.views.static.serve',
        {'document_root': '/path/to/media'}),

...onde site_media é a URL onde a sua mídia será mapeada, e /path/to/media é a pasta raiz para sua mídia. Isto irá chamar a view serve(), passando o caminho da URLconf e o parâmetro (obrigatório) document_root.

Dado o URLconf acima:

  • O arquivo /path/to/media/foo.jpg será mapeado para a URL /site_media/foo.jpg.
  • O arquivo /path/to/media/css/mystyles.css será mapeado para a URL /site_media/css/mystyles.css.
  • O arquivo /path/bar.jpg não será acessível, pois não é mapeado para a pasta raiz.

É claro, não é obrigatória a utilização de uma string fixa para o valor 'document_root'. Você pode querer ter uma variável em seu arquivo settings e usar o valor que estiver nela. Que permitirá a você e outros desenvolvedores trabalhar sobre o código facilmente, mudando o valor como quiserem. Por exemplo, se nós tivermos uma linha no settings.py que diz:

STATIC_DOC_ROOT = '/path/to/media'

...nós poderiamos escrever uma entrada URLconf desta forma:

from django.conf import settings
...
(r'^site_media/(?P<path>.*)$', 'django.views.static.serve',
        {'document_root': settings.STATIC_DOC_ROOT}),

Tome cuidado para não usar o mesmo caminho da sua configuração ADMIN_MEDIA_PREFIX (cujo padrão é /media/) já que isso irá sobrescrever sua entrada na configuração de URL.

Listagem de diretórios

Opcionalmente, você pode passar um parâmetro show_indexes para a view serve(). O valor padrão é False. Se for True, o Django exibirá uma listagem dos arquivos dos diretórios.

Exemplo:

(r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/path/to/media', 'show_indexes': True}),

Você pode customizar a exibição do índice criando um template chamado static/directory_index. Esse template recebe dois objetos em seu contexto:

  • directory – o nome do diretório (como string)
  • file_list – a lista de nomes de arquivos (como strings) no diretório

Aqui está o template static/directory_index.html padrão:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <meta http-equiv="Content-Language" content="en-us" />
    <meta name="robots" content="NONE,NOARCHIVE" />
    <title>Index of {{ directory }}</title>
</head>
<body>
    <h1>Index of {{ directory }}</h1>
    <ul>
    {% for f in file_list %}
    <li><a href="{{ f }}">{{ f }}</a></li>
    {% endfor %}
    </ul>
</body>
</html>
Antes do Django 1.0.3, havia um bug na visão que fornecia listagem de diretórios. O template que era carregado tinha de ser chamado static/directory_listing (sem extensão .html). Para compatibilidade retroativa, o Django ainda carrega templates com o nome antigo (sem extensão), mas irá preferir a versão directory_index.html, com extensão.

Limitando o uso para DEBUG=True

Como URLconfs são simples módulos Python, você pode usar lógica Python para fazer com que a exibição de arquivos estáticos seja possível apenas em fase de desenvolvimento. Esse é um truque útil para se certificar de que a exibição de arquivos estáticos não seja usada em modo de produção por engano.

Faça isso inserindo uma instrução if DEBUG em volta da inclusão do django.views.static.serve(). Aqui está um exemplo completo de URLconf:

from django.conf.urls.defaults import *
from django.conf import settings

urlpatterns = patterns('',
    (r'^articles/2003/$', 'news.views.special_case_2003'),
    (r'^articles/(?P<year>\d{4})/$', 'news.views.year_archive'),
    (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'news.views.month_archive'),
    (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d+)/$', 'news.views.article_detail'),
)

if settings.DEBUG:
    urlpatterns += patterns('',
        (r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/path/to/media'}),
    )

Este código é simples. Ele importa as configurações e checa o valor do DEBUG. Se for avaliado como True, então site_media será associada com a view django.views.static.serve. Caso contrário então a view não estará disponível.

Obviamente, a questão aqui é lembrar-se de colocar DEBUG=False no arquivo de configurações. Mas você já devia fazer isso de qualquer forma.