¿Por qué DEBUG = False setting hace que mi acceso a archivos estáticos django falle?

356

Estoy creando una aplicación usando Django como mi caballo de batalla. Todo ha ido bien hasta ahora: configuraciones de db especificadas, directorios estáticos configurados, URL, vistas, etc. Pero los problemas comenzaron a escabullirse en el momento en que quería presentar mis propias páginas 404.html y 500.html hermosas y personalizadas.

Leí los documentos sobre el manejo personalizado de errores y configuré las configuraciones necesarias en UrlsConf, creé las vistas correspondientes y agregué el 404.html y el 500.html al directorio de plantillas de mi aplicación (también especificado en settings.py).

Pero los documentos dicen you can actually view custom error views until Debug is Off, así que lo apagué para probar mis cosas, ¡y ahí es cuando las cosas se vuelven locas!

No solo no puedo ver el 404.html personalizado (en realidad, se carga, sino que debido a que mis páginas de error contienen un mensaje de error gráfico, como una buena imagen), se carga la fuente de la página de error, ¡pero nada más se carga! ¡Ni siquiera enlazó CSS ​​o Javascript!

En general, una vez que configuro DEBUG = False, todas las vistas se cargarán, ¡pero no se cargará ningún contenido vinculado (CSS, Javascript, Imágenes, etc.)! ¿Qué esta pasando? ¿Hay algo que falta, en relación con los archivos estáticos y la DEBUGconfiguración?

nemesisfixx
fuente
Como estas alojando Máquina local con el servidor de prueba?
j_syk
Máquina local con servidor de prueba. Básicamente quiero ver cómo funcionaría mi manejo de errores personalizado simulando localmente escenarios como acceder a páginas no existentes y causar errores en tiempo de ejecución, pero mi contenido estático no se cargará.
nemesisfixx
Se puede hacer a nivel de servidor como aquí o se puede manejar a nivel de Django agregando urlpattern. Encontré esta pregunta a continuación para el mismo problema. stackoverflow.com/questions/6405173/…
Pankaj Anand

Respuestas:

353

Con la depuración desactivada, Django ya no manejará archivos estáticos por usted; su servidor web de producción (Apache o algo así) debería encargarse de eso.

Marek Sapota
fuente
3
Esto realmente calma mi curiosidad, por lo que ahora tiene sentido, y de hecho puedo cuidarlo con Apache si es necesario. Pensé que era un problema con mi propia configuración. Gracias
nemesisfixx
55
Encontré esta respuesta muy útil. En caso de que alguien más se encuentre en mi misma situación (usando Google App Engine para la aplicación con nonrel django): no olvide actualizar app.yaml.
Lyndsey Ferguson
3
manejadores: - url: / static static_dir: static
Lyndsey Ferguson
476

Si aún necesita un servidor estático localmente (por ejemplo, para realizar pruebas sin depurar), puede ejecutar devserver en modo inseguro:

manage.py runserver --insecure
Dmitry Shevchenko
fuente
66
Si bien esta bandera funciona, no sirve el contenido de la carpeta
colectiva
55
Eso es magia Gracias señor, es un héroe. Esta respuesta debe fusionarse con la respuesta aceptada, ya que resuelve el problema sin tener que servir estática utilizando otra forma que no sea django.
Depado
1
Esto fue todo lo que necesitaba. Aunque la mejor práctica sería utilizar una variable de entorno para diferenciar entre el entorno de desarrollo y producción y la alternancia de depuración.
Neeraj Gupta
1
Tenga en cuenta: eso NO funcionará con ManifestStaticFilesStorage como code.djangoproject.com/ticket/19295
Andrea Rabbaglietti el
99
alguien puede decirme de que lo que es tan inseguro acerca de esta
Kavi Vaidya
36

Puede usar WhiteNoise para servir archivos estáticos en producción.

Instalar en pc:

pip install WhiteNoise

Y cambie su archivo wsgi.py a esto:

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

application = get_wsgi_application()
application = DjangoWhiteNoise(application)

¡Y estás listo para irte!

Crédito al blog creativo del manillar .

PERO, realmente no se recomienda servir archivos estáticos de esta manera en producción. Su servidor web de producción (como nginx) debería encargarse de eso.

Johnny Zhao
fuente
1
Suena interesante, pero no funcionó para mí simplemente agregando esa línea al wgsi.pyarchivo. La documentación que vinculó parece dar otras instrucciones para usar WhiteNoise. Intentaremos otras formas y te actualizaré aquí.
DarkCygnus
+1 ya que esto fue lo que finalmente me llevó a la solución. Agregué una respuesta donde incluí los pasos adicionales que tomé para que realmente funcione.
DarkCygnus
manage.py runserver --insecureNo funcionó para mí. Sin embargo, este sí.
Jee
3
Tenga en cuenta que con WhiteNoise versión 4.0, la configuración cambió. No agregue estas líneas a wsgi.py. En cambio, solo agregue 'whitenoise.middleware.WhiteNoiseMiddleware'al middleware. Vea las notas de la versión del registro de cambios
Doug Harris, el
¿Por qué no se recomienda *? Lo he estado usando durante años en varios sitios, funciona muy bien. Incluso Heroku lo usa en su plantilla Django.
Omar González
33

En urls.py agregué esta línea:

from django.views.static import serve 

agregue esas dos URL en patrones de URL:

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

y tanto los archivos estáticos como los medios eran accesibles cuando DEBUG = FALSE.
Espero eso ayude :)

Stathoula
fuente
Cuando terminó el panel de administración css no se carga?
Thusitha Deepal
Si. ¡El único que funciona! Gracias.
DrGeneral
¡INCREÍBLE! No olvide configurar STATIC_ROOT y manage.py collectstatic.
DomingoR
2
Hoy en día reemplazar url(conre_path(
Leopd
19

Si está utilizando la vista de servicio estático en desarrollo, debe tener DEBUG = True:

Advertencia

Esto solo funcionará si DEBUG es True.

Esto se debe a que esta visión es extremadamente ineficiente y probablemente insegura. Esto solo está destinado al desarrollo local, y nunca debe usarse en la producción.

Documentos: servir archivos estáticos en desarrollo

EDITAR: puede agregar algunas URL solo para probar sus plantillas 404 y 500, solo use la vista genérica direct_to_template en sus URL.

from django.views.generic.simple import direct_to_template

urlpatterns = patterns('',
    ('^404testing/$', direct_to_template, {'template': '404.html'})
)
j_syk
fuente
1
¿Cómo funciona uno, luego sirve los archivos estáticos en producción? NVM, acabo de ver eso. Gracias.
configuraría su servidor web para alojar un directorio específico. Lo más común es que use Apache o Nginx. Los doctores lo analizan un poco.
j_syk
gracias @j_syk, ya probé este enfoque de ver el 404.html y el 500.html a través de algún otro mecanismo sin errores similar a lo que sugieres. Pero quería saber si era totalmente imposible que mis páginas se procesaran correctamente como lo harían en producción, mientras seguía ejecutándose en mi servidor de prueba: la delegación del manejo de archivos estáticos a Apache cuando Debug está desactivado lo resuelve para mí. Gracias por contribuir
nemesisfixx
@mcnemesis No estoy seguro de lo que sucederá exactamente, pero intente configurar TEMPLATE_DEBUG = False y DEBUG = True. Si desactiva los errores bonitos, no estoy seguro de si va a las plantillas 404/500 en su lugar
j_syk
como se esperaba, hacer esto no arrojó ningún resultado positivo, pero aún así, gracias.
nemesisfixx
17

La respuesta de Johnny es genial, pero aún así no funcionó para mí simplemente agregando esas líneas que se describen allí. Basado en esa respuesta, los pasos que realmente funcionaron para mí fueron:

  1. Instale WhiteNoise como se describe:

    pip install WhiteNoise
  2. Cree la STATIC_ROOTvariable y agregue WhiteNoise a su MIDDLEWAREvariable en 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. Luego, modifique su wsgi.pyarchivo como se explica en la respuesta 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. Después de eso, implemente sus cambios en su servidor (con git o lo que sea que use).

  5. Finalmente, ejecute la collectstaticopción desde su manage.pyen su servidor. Esto copiará todos los archivos de sus carpetas estáticas en el STATIC_ROOTdirectorio que especificamos antes:

    $ python manage.py collectstatic

    Ahora verá una nueva carpeta llamada staticfilesque contiene dichos elementos.

Después de seguir estos pasos, ahora puede ejecutar su servidor y podrá ver sus archivos estáticos mientras está en modo Producción.

Actualización: en caso de que tenga la versión <4, el registro de cambios indica que ya no es necesario declararlo WSGI_APPLICATION = 'projectName.wsgi.application'en su settings.pyarchivo.

DarkCygnus
fuente
Lo hice en consecuencia, y en el desarrollo funcionó bien, pero no en producción. Todavía tengo el mismo problema cuando DEBUG == False
Anna Huang
@AnnaHuang ¿Qué quieres decir con desarrollo y producción? ¿Tiene ambientes o máquinas separadas? ¿Están configurados de la misma manera?
DarkCygnus
13

En realidad, puede servir archivos estáticos en una aplicación Django de producción, de forma segura y sin ellos DEBUG=True.

En lugar de usar Django, use dj_static en su archivo 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
fuente
2
Desde entonces descubrí whitenoise , que puede ser más completo.
Robin Winslow
7

Simplemente abra su proyecto urls.py, luego encuentre esta declaración if.

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

Puede cambiar settings.DEBUG en True y funcionará siempre. Pero si su proyecto es algo serio, entonces debe pensar en otras soluciones mencionadas anteriormente.

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

En django 1.10 puedes escribir así:

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
fuente
3
Su código es correcto, pero en Django 1.10, la configuración es para medios y estática es: urlpatterns + = [url (r '^ media / (? P <path>. *) $', Serve, {'document_root': settings .MEDIA_ROOT,}), url (r '^ static / (? P <path>. *) $', Serve, {'document_root': settings.STATIC_ROOT}),]
Roberth Solís
6

Puede depurar esto de muchas maneras diferentes. Aquí está mi enfoque.

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

Asegúrese de leer los documentos;)

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

Conrado
fuente
0

La compatibilidad con los argumentos de vista de cadena para url () está en desuso y se eliminará en Django 1.10

Mi solución es solo una pequeña corrección a la solución de Conrado anterior.

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
fuente
0

Aunque no es lo más seguro, puede cambiar el código fuente. navegar aPython/2.7/site-packages/django/conf/urls/static.py

Luego edite como sigue:

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

Entonces, si settings.debug==Falseno afecta el código, también después de ejecutar, intente python manage.py runserver --runserverejecutar archivos estáticos.

NOTA : La información solo debe usarse para pruebas solamente

Natuto
fuente
0

Hice los siguientes cambios en mi proyecto / urls.py y funcionó para mí

Agregue esta línea: desde django.conf.urls import url

y agregue: url (r '^ media / (? P. *) $', serve, {'document_root': settings.MEDIA_ROOT,}), en urlpatterns.

Namrata Sharma
fuente