Por que a configuração DEBUG = False faz com que o acesso estático a arquivos do django falhe?

356

Estou construindo um aplicativo usando o Django como meu cavalo de batalha. Tudo está bem até agora - configurações de banco de dados especificadas, diretórios estáticos, URLs, visualizações etc. Mas os problemas começaram a surgir no momento em que eu queria renderizar minhas próprias páginas 404.html e 500.html bonitas e personalizadas.

Li os documentos sobre tratamento de erros personalizados e defino as configurações necessárias no UrlsConf, criei as visualizações correspondentes e adicionei o 404.html e o 500.html ao diretório de modelos do meu aplicativo (especificado também em settings.py).

Mas os médicos dizem you can actually view custom error views until Debug is Off, então eu desliguei para testar minhas coisas, e é aí que as coisas ficam loucas!

Não só não consigo visualizar o 404.html personalizado (na verdade, ele carrega, mas porque minhas páginas de erro contêm uma mensagem de erro gráfica - como uma imagem legal), a fonte da página de erro carrega, mas nada mais carrega! Nem mesmo CSS ou Javascript vinculado!

Geralmente, assim que eu definir DEBUG = False, todas as visualizações serão carregadas, mas qualquer conteúdo vinculado (CSS, Javascript, Imagens, etc.) não será carregado! O que está acontecendo? Falta alguma coisa, relacionada aos arquivos estáticos e à DEBUGconfiguração?

nemesisfixx
fonte
Como você está hospedando? Máquina local com o servidor de teste?
Jsyk
máquina local com servidor de teste. Basicamente, quero ver como meu tratamento personalizado de erros funcionaria simulando localmente cenários como acessar páginas inexistentes e causar erros em tempo de execução - mas meu conteúdo estático não será carregado.
Nemesisfixx
Ou isso pode ser feito no nível do servidor, como aqui, ou pode ser tratado no nível do Django, adicionando urlpattern. Encontrei esta pergunta abaixo para o mesmo problema. stackoverflow.com/questions/6405173/…
Pankaj Anand

Respostas:

353

Com a depuração desativada, o Django não manipulará mais os arquivos estáticos - seu servidor Web de produção (Apache ou algo assim) deve cuidar disso.

Marek Sapota
fonte
3
Isso realmente acalma minha curiosidade, então agora faz sentido, e eu posso realmente cuidar disso com o Apache, se necessário. Eu pensei que era um problema com minhas próprias configurações. Graças
nemesisfixx
5
Achei esta resposta muito útil. Caso alguém esteja na minha mesma situação (usando o Google App Engine para o aplicativo com nonrel django): não esqueça de atualizar app.yaml.
Lyndsey Ferguson
3
manipuladores: - url: / static static_dir: static
Lyndsey Ferguson
475

Se você ainda precisa servidor estático localmente (por exemplo, para testar sem depuração), você pode executar o devserver no modo inseguro:

manage.py runserver --insecure
Dmitry Shevchenko
fonte
6
Embora esta bandeira não funciona, não serve o conteúdo da pasta collectstatic
Howie
5
Isso é mágico. Obrigado senhor, você é um herói. Esta resposta deve ser mesclada com a resposta aceita, pois resolve o problema sem precisar servir estático usando outra maneira que não o próprio django.
Depado
11
Era tudo o que eu precisava. Embora a melhor prática seja usar a variável de ambiente para diferenciar entre o ambiente de desenvolvimento e produção e a alternância de depuração.
precisa
11
Por favor, note: Isso é não funcionará com ManifestStaticFilesStorage como code.djangoproject.com/ticket/19295
Andrea Rabbaglietti
9
alguém pode me dizer se o que é tão inseguro sobre isso
Kavi Vaidya
36

Você pode usar o WhiteNoise para servir arquivos estáticos na produção.

Instalar:

pip install WhiteNoise

E mude seu arquivo wsgi.py para este:

from django.core.wsgi import get_wsgi_application
from whitenoise.django import DjangoWhiteNoise

application = get_wsgi_application()
application = DjangoWhiteNoise(application)

E você está pronto para ir!

Crédito para o Guiador Creative Blog .

MAS, não é realmente recomendável exibir arquivos estáticos dessa maneira na produção. Seu servidor web de produção (como o nginx) deve cuidar disso.

Johnny Zhao
fonte
11
Parece interessante, mas não funcionou para mim apenas adicionando essa linha ao wgsi.pyarquivo. A documentação que você vinculou parece fornecer outras instruções para o uso do WhiteNoise. Tentará outras formas e atualizará você aqui.
precisa saber é o seguinte
+1, pois foi isso que me levou à solução. Eu adicionei uma resposta onde incluí as etapas adicionais que eu tomei para realmente fazê-lo funcionar.
precisa saber é o seguinte
manage.py runserver --insecurenão funcionou para mim. Este faz, no entanto.
Jee
3
Observe que com o WhiteNoise versão 4.0, a configuração foi alterada. Não adicione essas linhas ao wsgi.py. Em vez disso, basta adicionar 'whitenoise.middleware.WhiteNoiseMiddleware'ao middleware. Veja as notas de versão do changelog
Doug Harris
Por que * não é recomendado? Eu tenho usado por anos em vários sites, funciona muito bem. Até o Heroku o usa no modelo do Django.
Omar Gonzalez
33

Em urls.py, adicionei esta linha:

from django.views.static import serve 

adicione esses dois URLs nos padrões de URL:

url(r'^media/(?P<path>.*)$', serve,{'document_root': settings.MEDIA_ROOT}), 
url(r'^static/(?P<path>.*)$', serve,{'document_root': settings.STATIC_ROOT}), 

e os arquivos estáticos e de mídia eram acessíveis quando DEBUG = FALSE.
Espero que ajude :)

Stathoula
fonte
Quando ele fez o painel de administração css não está carregando?
Thusitha Deepal
Sim. O único que funciona !! obrigado.
DrGeneral 02/09/19
IMPRESSIONANTE! Não se esqueça de definir STATIC_ROOT e manage.py collectstatic.
DomingoR
2
Hoje em dia substituir url(comre_path(
Leopd
19

Se você estiver usando a exibição estática de veiculação em desenvolvimento, precisará DEBUG = True:

Atenção

Isso funcionará apenas se DEBUG for True.

Isso ocorre porque essa visão é grosseiramente ineficiente e provavelmente insegura. Isso é destinado apenas ao desenvolvimento local e nunca deve ser usado na produção.

Documentos: servindo arquivos estáticos em desenvolvedores

EDIT: você pode adicionar alguns URLs apenas para testar seus modelos 404 e 500, basta usar a visualização genérica direct_to_template em seus URLs.

from django.views.generic.simple import direct_to_template

urlpatterns = patterns('',
    ('^404testing/$', direct_to_template, {'template': '404.html'})
)
j_syk
fonte
11
Como é que alguém serve os arquivos estáticos na produção? NVM, acabei de ver isso. Obrigado.
você configuraria seu servidor da web para hospedar um diretório específico. Mais comumente, você usaria Apache ou Nginx. Os Docs investigam um pouco.
Jsyk
obrigado @j_syk, eu já tinha tentado essa abordagem de visualizar o 404.html e 500.html através de algum outro mecanismo sem erro semelhante ao que você sugere. Mas eu queria saber se era totalmente impossível que minhas páginas fossem renderizadas corretamente como na produção, enquanto ainda estavam sendo executadas no meu servidor de teste - a delegação de manipulação de arquivo estática para o Apache quando Debug está desativado. Obrigado por contribuir.
Nemesisfixx
@mcnemesis Não sei exatamente o que vai acontecer, mas tente definir TEMPLATE_DEBUG = False e DEBUG = True. Se você desligar as bonitas erros não tenho certeza se ele vai para os 404/500 modelos em vez
j_syk
Como esperado, isso não produziu nenhum resultado positivo.
Nemesisfixx
17

A resposta de Johnny é ótima, mas ainda não funcionou para mim apenas adicionando as linhas descritas lá. Com base nessa resposta, as etapas que realmente funcionaram para mim onde:

  1. Instale o WhiteNoise conforme descrito:

    pip install WhiteNoise
  2. Crie a STATIC_ROOTvariável e adicione WhiteNoise à sua MIDDLEWAREvariável em settings.py:

    #settings.py
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'whitenoise.middleware.WhiteNoiseMiddleware', #add whitenoise
        'django.contrib.sessions.middleware.SessionMiddleware',
        ...
    ]
    
    #...
    
    STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') ##specify static root
  3. Em seguida, modifique seu wsgi.pyarquivo conforme explicado na resposta de Johnny:

    #wsgi.py
    from django.core.wsgi import get_wsgi_application
    from whitenoise.django import DjangoWhiteNoise
    
    application = get_wsgi_application()
    application = DjangoWhiteNoise(application)
  4. Depois disso, implante suas alterações no servidor (com git ou o que você usar).

  5. Por fim, execute a collectstaticopção manage.pyno seu servidor. Isso copiará todos os arquivos de suas pastas estáticas no STATIC_ROOTdiretório especificado anteriormente:

    $ python manage.py collectstatic

    Você verá uma nova pasta chamada staticfilesque contém esses elementos.

Depois de seguir estas etapas, você poderá executar o servidor e poderá ver seus arquivos estáticos no modo de produção.

Update: No caso de você tinha a versão <4 o changelog indica que ele não é mais necessário declarar o WSGI_APPLICATION = 'projectName.wsgi.application'no seu settings.pyarquivo.

DarkCygnus
fonte
Fiz isso de acordo e, no desenvolvimento, serviu bem, mas não na produção. Ainda tem o mesmo problema quando DEBUG == False #
Anna Huang
@AnnaHuang O que você quer dizer com desenvolvimento e produção? Você tem ambientes ou máquinas separados? Eles estão configurados da mesma maneira?
DarkCygnus 17/09/19
13

Você pode realmente servir arquivos estáticos em um aplicativo Django de produção, com segurança e sem DEBUG=True.

Em vez de usar o próprio Django, use dj_static no seu arquivo WSGI ( github ):

# requirements.txt:

...
dj-static==0.0.6


# YOURAPP/settings.py:

...
STATIC_ROOT = 'staticdir'
STATIC_URL = '/staticpath/'

# YOURAPP/wsgi.py:

...
from django.core.wsgi import get_wsgi_application
from dj_static import Cling

application = Cling(get_wsgi_application())
Robin Winslow
fonte
2
Desde então, descobri o whitenoise , que pode ser mais completo.
Robin Winslow
7

Basta abrir o projeto urls.py e, em seguida, encontre esta instrução if.

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

Você pode alterar o settings.DEBUG em True e ele sempre funcionará. Mas se o seu projeto é algo sério, você deve pensar em outras soluções mencionadas acima.

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

No django 1.10, você pode escrever assim:

urlpatterns += [ url(r'^media/(?P<path>.*)$', serve, { 'document_root': settings.MEDIA_ROOT, }), url(r'^static/(?P<path>.*)$', serve, { 'document_root': settings.STATIC_ROOT }), ]
Sergey Luchko
fonte
3
Seu código está correto, mas no Django 1.10, a configuração é para media e estática é: urlpatterns + = [url (r '^ media / (? P <caminho>. *) $', Serve, {'document_root': settings .MEDIA_ROOT,}), url (r '^ static / (? P <path>. *) $', Serve, {'document_root': settings.STATIC_ROOT}),]
Roberth Solís
6

Você pode depurar isso de várias maneiras diferentes. Aqui está a minha abordagem.

localsettings.py:

DEBUG = False
DEBUG404 = True

urls.py:

from django.conf import settings
import os

if settings.DEBUG404:
    urlpatterns += patterns('',
        (r'^static/(?P<path>.*)$', 'django.views.static.serve',
         {'document_root': os.path.join(os.path.dirname(__file__), 'static')} ),
    )

Certifique-se de ler os documentos;)

https://docs.djangoproject.com/en/2.0/howto/static-files/#limiting-use-to-debug-true

Conrado
fonte
0

O suporte a argumentos de exibição de string para url () está obsoleto e será removido no Django 1.10

Minha solução é apenas uma pequena correção para a solução Conrado acima.

from django.conf import settings
import os
from django.views.static import serve as staticserve

if settings.DEBUG404:
    urlpatterns += patterns('',
        (r'^static/(?P<path>.*)$', staticserve,
            {'document_root': os.path.join(os.path.dirname(__file__), 'static')} ),
        )
be_good_do_good
fonte
0

Embora não seja mais seguro, você pode alterar o código fonte. navegar paraPython/2.7/site-packages/django/conf/urls/static.py

Em seguida, edite da seguinte forma:

if settings.DEBUG or (prefix and '://' in prefix):

Portanto, se settings.debug==Falsenão tiver efeito no código, também após a execução, tente python manage.py runserver --runserverexecutar arquivos estáticos.

NOTA : As informações devem ser usadas apenas para teste apenas

Natuto
fonte
0

Fiz as seguintes alterações no meu projeto / urls.py e funcionou para mim

Adicione esta linha: de django.conf.urls import url

e adicione: url (r '^ media / (? P. *) $', serve, {'document_root': settings.MEDIA_ROOT,}), em urlpatterns.

Namrata Sharma
fonte