Django, creando una página de error personalizada 500/404

105

Siguiendo el tutorial que se encuentra aquí exactamente, no puedo crear una página de error personalizada 500 o 404. Si escribo una URL incorrecta, la página me da la página de error predeterminada. ¿Hay algo que deba comprobar que evite que aparezca una página personalizada?

Directorios de archivos:

mysite/
    mysite/
        __init__.py
        __init__.pyc
        settings.py
        settings.pyc
        urls.py
        urls.pyc
        wsgi.py
        wsgi.pyc
    polls/
        templates/
            admin/
                base_site.html
            404.html
            500.html
            polls/
                detail.html
                index.html
        __init__.py
        __init__.pyc
        admin.py
        admin.pyc
        models.py
        models.pyc
        tests.py
        urls.py
        urls.pyc
        view.py
        views.pyc
    templates/
    manage.py

dentro de mysite / settings.py tengo estos habilitados:

DEBUG = False
TEMPLATE_DEBUG = DEBUG

#....

TEMPLATE_DIRS = (
    'C:/Users/Me/Django/mysite/templates', 
)

dentro de mysite / polls / urls.py:

from django.conf.urls import patterns, url

from polls import views

urlpatterns = patterns('',
    url(r'^$', views.index, name='index'),
    url(r'^(?P<poll_id>\d+)/$', views.detail, name='detail'),
    url(r'^(?P<poll_id>\d+)/results/$', views.results, name='results'),
    url(r'^(?P<poll_id>\d+)/vote/$', views.vote, name='vote'),
)

Puedo publicar cualquier otro código necesario, pero ¿qué debo cambiar para obtener una página de error 500 personalizada si uso una URL incorrecta?

Editar

SOLUCIÓN: Tuve un adicional

TEMPLATE_DIRS

dentro de mi settings.py y eso estaba causando el problema

Zac
fuente
1
La depuración está configurada en False en mi código
Zac
Esto podría ayudarlo a stackoverflow.com/a/12180499/1628832
karthikr
1
Encontré esta respuesta mientras buscaba la manera de hacer solo una plantilla personalizada y quería compartir un poco de documentación de Django que me ayudó mucho; docs.djangoproject.com/en/1.7/ref/views/…
Blackeagle52
El mío funcionó sin la configuración template_dirs.
Programmingjoe
1
Puntos para la ironía cuando el enlace en la primera línea conduce a la página 404 de Django. Conduce a una página de tutorial para una versión de Django que no existe, creo. Aquí está el enlace a la página del tutorial para Django 2.0: docs.djangoproject.com/en/2.0/intro/tutorial03
andrewec

Respuestas:

120

Debajo de su principal, views.pyagregue su propia implementación personalizada de las siguientes dos vistas, y simplemente configure las plantillas 404.html y 500.html con lo que desea mostrar.

Con esta solución, no es necesario agregar ningún código personalizado a urls.py

Aquí está el código:

from django.shortcuts import render_to_response
from django.template import RequestContext


def handler404(request, *args, **argv):
    response = render_to_response('404.html', {},
                                  context_instance=RequestContext(request))
    response.status_code = 404
    return response


def handler500(request, *args, **argv):
    response = render_to_response('500.html', {},
                                  context_instance=RequestContext(request))
    response.status_code = 500
    return response

Actualizar

handler404y handler500se exportan las variables de configuración de cadenas de Django que se encuentran en django/conf/urls/__init__.py. Es por eso que funciona la configuración anterior.

Para que la configuración anterior funcione, debe definir las siguientes variables en su urls.pyarchivo y apuntar las variables de Django exportadas a la ruta de Python de cadena de donde se definen estas vistas funcionales de Django, así:

# project/urls.py

handler404 = 'my_app.views.handler404'
handler500 = 'my_app.views.handler500'

Actualización para Django 2.0

Las firmas para las vistas del controlador se cambiaron en Django 2.0: https://docs.djangoproject.com/en/2.0/ref/views/#error-views

Si usa vistas como arriba, handler404 fallará con el mensaje:

"handler404 () obtuvo un argumento de palabra clave inesperado 'excepción'"

En tal caso, modifique sus vistas de esta manera:

def handler404(request, exception, template_name="404.html"):
    response = render_to_response(template_name)
    response.status_code = 404
    return response
Aaron Lelevier
fuente
Esto pareció funcionar bastante bien para mí, pero por alguna razón request.user parece estar bien en la plantilla 404, pero no en absoluto en la plantilla 500 (y son casi idénticas) - pregunta publicada sobre esto aquí: stackoverflow.com/ preguntas / 26043211 /…
Gravity Grave
1
Otra cosa que me estaba preguntando: ¿qué pasa si usa el backend de administración y desea usar plantillas separadas para ellos? Que yo sepa, admin no tiene un views.py para anular y poner este fragmento de código en.
Gravedad grave
11
@GravityGrave 500 templateno se procesará request.userporque informa un error de servidor 500, por lo que el servidor no puede ofrecer nada.
Aaron Lelevier
5
No funcionó para mí con django 1.9; (Tal vez estoy haciendo algo mal. ¿Handler404 es un nombre reservado de django? ¿Cómo sabría django que debería llamar exactamente a esa vista?
deathangel908
1
Actualicé la respuesta en base a tu comentario. Lamento que la actualización llegue tan tarde. Espero que esto ayude.
Aaron Lelevier
71

Respuesta oficial:

Aquí está el enlace a la documentación oficial sobre cómo configurar vistas de error personalizadas:

https://docs.djangoproject.com/en/stable/topics/http/views/#customizing-error-views

Dice que agregue líneas como estas en su URLconf (configurarlas en cualquier otro lugar no tendrá ningún efecto):

handler404 = 'mysite.views.my_custom_page_not_found_view'
handler500 = 'mysite.views.my_custom_error_view'
handler403 = 'mysite.views.my_custom_permission_denied_view'
handler400 = 'mysite.views.my_custom_bad_request_view'

También puede personalizar la vista de errores CSRF modificando la configuración CSRF_FAILURE_VIEW.

Controladores de errores predeterminados:

Vale la pena leer la documentación de los controladores de errores por omisión, page_not_found, server_error, permission_deniedy bad_request. De manera predeterminada, utilizan estas plantillas si pueden encontrarlos, respectivamente: 404.html, 500.html, 403.html, y 400.html.

Entonces, si todo lo que quiere hacer es crear páginas de error bonitas, simplemente cree esos archivos en un TEMPLATE_DIRSdirectorio, no necesita editar URLConf en absoluto. Lea la documentación para ver qué variables de contexto están disponibles.

En Django 1.10 y versiones posteriores, la vista de error CSRF predeterminada usa la plantilla 403_csrf.html.

Gotcha:

No olvide que DEBUGdebe establecerse en False para que funcionen, de lo contrario, se utilizarán los controladores de depuración normales.

Flimm
fuente
1
Agregué, pero no funciona. Se agregó el handler404 y otros que apuntan a los lugares correctos en mis vistas, pero no funciona, todavía veo el 404. Y sí, estoy en modo Debug False y uso 1.9
KhoPhi
Usando Django 1.9 y simplemente agregando 500.html, etc., las plantillas las muestra en lugar de las páginas estándar. Buena solución fácil.
curtisp
2
Gotcha me ayudó. Funcionó al hacer estos cambios en mi settings.py, establecer DEBUG = False y ALLOWED_HOSTS = ['0.0.0.0'] para aceptar la solicitud http de cualquier cliente.
shaffooo
1
En caso de que alguien más se pregunte dónde diablos está URLconf, aquí está
Arthur Tarasov
38

Agregue estas líneas en urls.py

urls.py

from django.conf.urls import (
handler400, handler403, handler404, handler500
)

handler400 = 'my_app.views.bad_request'
handler403 = 'my_app.views.permission_denied'
handler404 = 'my_app.views.page_not_found'
handler500 = 'my_app.views.server_error'

# ...

e implementar nuestras vistas personalizadas en views.py.

views.py

from django.shortcuts import (
render_to_response
)
from django.template import RequestContext

# HTTP Error 400
def bad_request(request):
    response = render_to_response(
        '400.html',
        context_instance=RequestContext(request)
        )

        response.status_code = 400

        return response

# ...
Armance
fuente
5
¿Por qué importaría handler400solo para sobrescribirlo handler400 = 'myapp.views.bad_request'?
Flimm
5
No es necesario importar los controladores aquí para anularlos.
funkotron
1
No deberías usar render_to_response. De los documentos: "no se recomienda y es probable que quede obsoleto en el futuro".
Timmy O'Mahony
Para Django 1.10, ya render_to_responseque estará obsoleto, consulte lo siguiente (use renderen su lugar): stackoverflow.com/questions/44228397/…
mrdaliri
21

De la página a la que hizo referencia:

Cuando genere Http404 desde una vista, Django cargará una vista especial dedicada al manejo de errores 404. Lo encuentra buscando la variable handler404 en su URLconf raíz (y solo en su URLconf raíz; configurar handler404 en cualquier otro lugar no tendrá ningún efecto), que es una cadena en la sintaxis de puntos de Python, el mismo formato que usan las devoluciones de llamada URLconf normales. Una vista 404 en sí misma no tiene nada especial: es solo una vista normal.

Entonces creo que debes agregar algo como esto a tu urls.py:

handler404 = 'views.my_404_view'

y similar para handler500.

Mike Pelley
fuente
¿Cómo se ve eso, Mike? Hoy es mi primer día usando Django y todavía estoy colgando de las cuerdas
Zac
2
@JimRilye Deberá agregar una función 500 adecuada a sus vistas y luego hacer referencia a ella con esa variable. Entonces, encima de su urlpatterns = ...línea, agregue una línea que diga handler500 = 'views.handle500', y luego agregue def handle500(request):a su views.py que muestra su 500.html.
Mike Pelley
18

Si todo lo que necesita es mostrar páginas personalizadas que tienen algunos mensajes de error elegantes para su sitio cuando DEBUG = False, agregue dos plantillas llamadas 404.html y 500.html en su directorio de plantillas y automáticamente recogerá estas páginas personalizadas cuando un 404 o 500 es elevado.

Krishna G Nair
fuente
1
Esto funciona, solo asegúrese de tener algo como: 'DIRS': [os.path.join(BASE_DIR, '<project_name>/templates')]en su lista de PLANTILLAS en formato settings.py.
Eric
12

En Django 2. * puedes usar esta construcción en views.py

def handler404(request, exception):
    return render(request, 'errors/404.html', locals())

En settings.py

DEBUG = False

if DEBUG is False:
    ALLOWED_HOSTS = [
        '127.0.0.1:8000',
        '*',
    ]

if DEBUG is True:
    ALLOWED_HOSTS = []

En urls.py

# https://docs.djangoproject.com/en/2.0/topics/http/views/#customizing-error-views
handler404 = 'YOUR_APP_NAME.views.handler404'

Por lo general, creo default_app y manejo errores en todo el sitio, procesadores de contexto en él.

Guarida
fuente
Trabaja para mi. ¿Pero cuál es el exception?
zeleven
Según el enlace de documentación: docs.djangoproject.com/en/2.1/ref/urls/… . Está escrito: asegúrese de que el controlador acepte argumentos de solicitud y excepción
Alouani Younes
1
Me funcionó en Django 3.0 . Pero lo que es locals()? El archivo solo muestra pass.
mejora
9

settings.py:

DEBUG = False
TEMPLATE_DEBUG = DEBUG
ALLOWED_HOSTS = ['localhost']  #provide your host name

y simplemente agregue sus páginas 404.htmly 500.htmlen la carpeta de plantillas. eliminar 404.htmly 500.htmlde las plantillas en la aplicación de encuestas.

Rakesh babu
fuente
También está disponible cómo utilizar el mensaje de raise Http404('msg'): stackoverflow.com/a/37109914/895245 {{ request_path }} .
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
TEMPLATE_DEBUG se elimina de django2 docs.quantifiedcode.com/python-anti-patterns/django/1.8/…
Steve W
7

Comete un error, en la página de error averigüe desde dónde está cargando django las plantillas. Me refiero a la pila de rutas. En base template_dir agregue estas páginas html 500.html , 404.html . Cuando ocurren estos errores, los archivos de plantilla respectivos se cargarán automáticamente.

También puede agregar páginas para otros códigos de error, como 400 y 403 .

Espero que esto ayude !!!

allsyed
fuente
6

En Django 3.x, la respuesta aceptada no funcionará porque render_to_responsese ha eliminado por completo y se han realizado algunos cambios más desde la versión para la que funcionó la respuesta aceptada.

Algunas otras respuestas también están allí, pero presento una respuesta un poco más limpia:

En su urls.pyarchivo principal :

handler404 = 'yourapp.views.handler404'
handler500 = 'yourapp.views.handler500'

En yourapp/views.pyarchivo:

def handler404(request, exception):
    context = {}
    response = render(request, "pages/errors/404.html", context=context)
    response.status_code = 404
    return response


def handler500(request):
    context = {}
    response = render(request, "pages/errors/500.html", context=context)
    response.status_code = 500
    return response

Asegúrese de haber importado render()en yourapp/views.pyarchivo:

from django.shortcuts import render

Nota al margen: render_to_response()quedó obsoleto en Django 2.xy se ha eliminado por completo en la versión 3.x.

Rehmat
fuente
5

Como una sola línea (para la página 404 genérica):

from django.shortcuts import render_to_response
from django.template import RequestContext

return render_to_response('error/404.html', {'exception': ex},
                                      context_instance=RequestContext(request), status=404)
FireZenk
fuente
1
¿Y dónde usarlo?
Sami
4
# views.py
def handler404(request, exception):
    context = RequestContext(request)
    err_code = 404
    response = render_to_response('404.html', {"code":err_code}, context)
    response.status_code = 404
    return response

# <project_folder>.urls.py
handler404 = 'todo.views.handler404' 

Esto funciona en django 2.0

Asegúrese de incluir su personalizado 404.htmldentro de la carpeta de plantillas de la aplicación.

ENDEESA
fuente
4

Django 3.0

aquí hay un enlace sobre cómo personalizar las vistas de error

aquí hay un enlace sobre cómo renderizar una vista

en el urls.py(el principal, en la carpeta del proyecto), ponga:

handler404 = 'my_app_name.views.custom_page_not_found_view'
handler500 = 'my_app_name.views.custom_error_view'
handler403 = 'my_app_name.views.custom_permission_denied_view'
handler400 = 'my_app_name.views.custom_bad_request_view'

y en esa aplicación ( my_app_name) ponga views.py:

def custom_page_not_found_view(request, exception):
    return render(request, "errors/404.html", {})

def custom_error_view(request, exception=None):
    return render(request, "errors/500.html", {})

def custom_permission_denied_view(request, exception=None):
    return render(request, "errors/403.html", {})

def custom_bad_request_view(request, exception=None):
    return render(request, "errors/400.html", {})

NOTA: error/404.htmles la ruta si coloca sus archivos en la carpeta de plantillas de proyectos (no en las aplicaciones), templates/errors/404.htmlasí que coloque los archivos donde desee y escriba la ruta correcta.

NOTA 2: Después de volver a cargar la página, si aún ve la plantilla anterior, cámbiela settings.py DEBUG=True, guárdela y luego vuelva a False(para reiniciar el servidor y recopilar los archivos nuevos).

elano7
fuente
Nota adicional: si está ejecutando DEUB=Falsesus archivos estáticos, es posible que no se sirvan, por lo que no puede obtener una vista previa de los cambios de la plantilla de error personalizada. Úselo ./manage.py runserver --insecurepara forzar a django a servirlos de todos modos.
Rob
4

No se requiere vista adicional. https://docs.djangoproject.com/en/3.0/ref/views/

Simplemente coloque los archivos de error en la raíz del directorio de plantillas

  • 404.html
  • 400.html
  • 403.html
  • 500.html

Y debería usar su página de error cuando la depuración es Falsa

Anuj TBE
fuente
3

Intente mover sus plantillas de error a .../Django/mysite/templates/?

Estoy seguro de esto, pero creo que deben ser "globales" para el sitio web.

astrognocci
fuente