Django, criando uma página de erro 500/404 personalizada

105

Seguindo exatamente o tutorial encontrado aqui , não consigo criar uma página de erro 500 ou 404 personalizada. Se eu digitar um url incorreto, a página me mostra a página de erro padrão. Há algo que eu deveria verificar para evitar que uma página personalizada seja exibida?

Diretórios de arquivos:

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

em mysite / settings.py eu habilitei estes:

DEBUG = False
TEMPLATE_DEBUG = DEBUG

#....

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

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

Posso postar qualquer outro código necessário, mas o que devo mudar para obter uma página de erro 500 personalizada se usar um URL incorreto?

Editar

SOLUÇÃO: eu tinha um adicional

TEMPLATE_DIRS

em meu settings.py e isso estava causando o problema

Zac
fonte
1
Debug está definido como False em meu código
Zac
Isso pode ajudá-lo a stackoverflow.com/a/12180499/1628832
karthikr
1
Encontrei esta resposta enquanto procurava uma maneira de fazer apenas um template customizado e queria compartilhar um pouco da documentação do Django que me ajudou muito; docs.djangoproject.com/en/1.7/ref/views/…
Blackeagle52
O meu funcionou sem a configuração template_dirs.
Programmingjoe
1
Pontos para ironia quando o link na primeira linha leva à página 404 do Django. Leva a uma página de tutorial para uma versão do Django que não existe, eu acho. Aqui está o link para a página do tutorial do Django 2.0: docs.djangoproject.com/en/2.0/intro/tutorial03
andrewec

Respostas:

120

Em seu principal, views.pyadicione sua própria implementação personalizada das duas visualizações a seguir e apenas configure os modelos 404.html e 500.html com o que deseja exibir.

Com esta solução, nenhum código personalizado precisa ser adicionado ao urls.py

Aqui está o 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

Atualizar

handler404e handler500são exportadas variáveis ​​de configuração de string Django encontradas emdjango/conf/urls/__init__.py . É por isso que a configuração acima funciona.

Para fazer com que a configuração acima funcione, você deve definir as seguintes variáveis ​​em seu urls.pyarquivo e apontar as variáveis ​​exportadas do Django para o caminho do Python da string de onde essas visualizações funcionais do Django são definidas, como:

# project/urls.py

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

Atualização para Django 2.0

As assinaturas para visualizações do manipulador foram alteradas no Django 2.0: https://docs.djangoproject.com/en/2.0/ref/views/#error-views

Se você usar visualizações como acima, o handler404 falhará com a mensagem:

"handler404 () obteve um argumento de palavra-chave inesperado 'exceção'"

Nesse caso, modifique suas opiniões da seguinte forma:

def handler404(request, exception, template_name="404.html"):
    response = render_to_response(template_name)
    response.status_code = 404
    return response
Aaron Lelevier
fonte
Isso pareceu funcionar muito bem para mim, mas por algum motivo request.user aparece bem no modelo 404, mas não no modelo 500 (e eles são quase idênticos) - poste uma pergunta sobre isso aqui: stackoverflow.com/ perguntas / 26043211 /…
Sepultura Gravitacional
1
Outra coisa que eu estava pensando - e se você usar o back-end do administrador e quiser usar modelos separados para eles? Que eu saiba, o administrador não tem um views.py para substituir e colocar esse trecho de código.
Gravity Grave
11
@GravityGrave o 500 templatenão renderiza request.userporque está relatando um erro de servidor 500, então o servidor não é capaz de servir nada.
Aaron Lelevier
5
Não funcionou para mim com django 1.9; (Talvez eu esteja fazendo algo errado. Handler404 django é um nome reservado? Como django saberia que deveria chamar exatamente essa visão?
deathangel908
1
Eu atualizei a resposta com base em seu comentário. Desculpe que a atualização esteja tão atrasada. Eu espero que isso ajude.
Aaron Lelevier
71

Resposta oficial:

Aqui está o link para a documentação oficial sobre como configurar visualizações de erro personalizadas:

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

Diz para adicionar linhas como essas em seu URLconf (configurá-las em qualquer outro lugar não terá efeito):

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'

Você também pode personalizar a visualização do erro CSRF, modificando a configuração CSRF_FAILURE_VIEW.

Manipuladores de erro padrão:

Vale a pena ler a documentação dos manipuladores de erro padrão, page_not_found, server_error, permission_deniede bad_request. Por padrão, eles usam esses modelos se eles podem encontrá-los, respectivamente: 404.html, 500.html, 403.html, e 400.html.

Então, se tudo o que você quer fazer é criar belas páginas de erro, basta criar esses arquivos em um TEMPLATE_DIRS diretório, você não precisa editar o URLConf de forma alguma. Leia a documentação para ver quais variáveis ​​de contexto estão disponíveis.

No Django 1.10 e posterior, a visualização de erro CSRF padrão usa o modelo 403_csrf.html.

Peguei vocês:

Não se esqueça de que DEBUGdeve ser definido como False para que funcionem, caso contrário, os manipuladores de depuração normais serão usados.

Flimm
fonte
1
Eu adicionei, mas não funciona. Adicionado o handler404 e outros apontando para os lugares certos em minhas visualizações, mas não funciona, ainda vendo o padrão 404. E sim, estou no modo Debug False e usando 1.9
KhoPhi
Usar Django 1.9 e simplesmente adicionar 500.html templates etc mostra-os ao invés de páginas padrão. Boa solução fácil.
curtisp
2
Gotcha me ajudou. Funcionou fazendo essas alterações em meu settings.py, defina DEBUG = False e ALLOWED_HOSTS = ['0.0.0.0'] para aceitar a solicitação de http de qualquer cliente.
shaffooo
1
Caso alguém esteja se perguntando onde está o URLconf, aqui está
Arthur Tarasov
38

Adicione essas linhas em 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 nossas visualizações personalizadas em 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
fonte
5
Por que você importaria handler400apenas para sobrescrever handler400 = 'myapp.views.bad_request'?
Flimm
5
Você não precisa importar os manipuladores aqui para substituí-los.
funkotron
1
Você não deve usar render_to_response. Dos documentos: "não é recomendado e provavelmente será descontinuado no futuro."
Timmy O'Mahony,
Para Django 1.10, como render_to_responsevai ser descontinuado, consulte o seguinte (use em rendervez disso): stackoverflow.com/questions/44228397/…
mrdaliri
21

Na página que você referiu:

Quando você cria o Http404 de dentro de uma visão, o Django carrega uma visão especial dedicada a lidar com erros 404. Ele o encontra procurando pela variável handler404 em seu URLconf root (e apenas em seu URLconf root; definir handler404 em qualquer outro lugar não terá efeito), que é uma string na sintaxe com pontos do Python - o mesmo formato que os callbacks URLconf normais usam. Uma visão 404 em si não tem nada de especial: é apenas uma visão normal.

Portanto, acredito que você precisa adicionar algo assim ao seu urls.py:

handler404 = 'views.my_404_view'

e semelhante para handler500.

Mike Pelley
fonte
Como isso parece Mike? Hoje é meu primeiro dia usando Django e ainda estou me segurando nas cordas
Zac
2
@JimRilye Você precisará adicionar uma função 500 adequada às suas visualizações e, em seguida, referenciá-la com essa variável. Portanto, acima de sua urlpatterns = ...linha, adicione uma linha que diga handler500 = 'views.handle500'e, em seguida, adicione um def handle500(request):ao seu views.py que exibe seu 500.html.
Mike Pelley
18

Se tudo o que você precisa é mostrar páginas personalizadas que têm algumas mensagens de erro sofisticadas para o seu site quando DEBUG = False, então adicione dois modelos chamados 404.html e 500.html no seu diretório de modelos e ele irá selecionar automaticamente essas páginas personalizadas quando um 404 ou 500 é gerado.

Krishna G Nair
fonte
1
Isso funciona, apenas certifique-se de ter algo como: 'DIRS': [os.path.join(BASE_DIR, '<project_name>/templates')]em sua lista de TEMPLATES no settings.py.
Eric,
12

No Django 2. * você pode usar esta construção em views.py

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

Em settings.py

DEBUG = False

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

if DEBUG is True:
    ALLOWED_HOSTS = []

Em urls.py

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

Normalmente eu crio default_app e lido com erros de todo o site, processadores de contexto nele.

DeN
fonte
Trabalhe para mim. Mas o que é exception?
zeleven
De acordo com o link de documentação: docs.djangoproject.com/en/2.1/ref/urls/… . Está escrito: certifique-se de que o gerenciador aceita os argumentos de solicitação e exceção
Alouani Younes
1
Trabalhou para mim no Django 3.0 . Mas o que é locals()? O arquivo só mostra pass.
enchance
9

settings.py:

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

e apenas adicione suas páginas 404.htmle 500.htmlna pasta de modelos. remover 404.htmle 500.htmlde modelos no aplicativo de enquetes.

Rakesh babu
fonte
Como usar a mensagem de raise Http404('msg'): stackoverflow.com/a/37109914/895245 {{ request_path }} também está disponível.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
TEMPLATE_DEBUG foi removido de django2 docs.quantifiedcode.com/python-anti-patterns/django/1.8/…
Steve W
7

Cometa um erro, na página de erro, descubra de onde django está carregando os modelos. Quero dizer, a pilha de caminhos. No template_dir base, adicione essas páginas html 500.html , 404.html . Quando esses erros ocorrerem, os respectivos arquivos de modelo serão carregados automaticamente.

Você também pode adicionar páginas para outros códigos de erro, como 400 e 403 .

Espero esta ajuda !!!

allsyed
fonte
6

No Django 3.x, a resposta aceita não funcionará porque render_to_responsefoi removida completamente, assim como mais algumas mudanças foram feitas desde a versão para a qual a resposta aceita funcionou.

Algumas outras respostas também estão lá, mas estou apresentando uma resposta um pouco mais clara:

Em seu urls.pyarquivo principal :

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

No yourapp/views.pyarquivo:

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

Certifique-se de ter importado render()no yourapp/views.pyarquivo:

from django.shortcuts import render

Nota lateral: render_to_response()foi descontinuado no Django 2.xe foi completamente removido na versão 3.x.

Rehmat
fonte
5

Como uma única linha (para a 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
fonte
1
E onde usar?
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' 

Isso funciona no django 2.0

Certifique-se de incluir seu personalizado 404.htmldentro da pasta de modelos de aplicativos.

ENDEESA
fonte
4

Django 3.0

aqui está o link para personalizar visualizações de erros

aqui está o link como renderizar uma visualização

no urls.py(o principal, na pasta do projeto), coloque:

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'

e nesse aplicativo ( my_app_name) coloque 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.htmlé o caminho se você colocar seus arquivos na pasta de modelos de projetos (não nos aplicativos), templates/errors/404.htmlportanto, coloque os arquivos onde quiser e escreva o caminho correto.

NOTA 2: Depois de recarregar a página, se você ainda vir o modelo antigo, altere-o settings.py DEBUG=True, salve-o e depois novamente em False(para reiniciar o servidor e coletar os novos arquivos).

elano7
fonte
Observação extra: se você estiver executando em DEUB=Falseseus arquivos estáticos, pode não ser veiculado, fazendo com que você não possa visualizar as alterações do modelo de erro personalizado. Use ./manage.py runserver --insecurepara forçar o Django a servi-los de qualquer maneira.
Rob
4

Nenhuma visão adicional é necessária. https://docs.djangoproject.com/en/3.0/ref/views/

Basta colocar os arquivos de erro na raiz do diretório de modelos

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

E ele deve usar sua página de erro quando a depuração for False

Anuj TBE
fonte
3

Tente mover seus modelos de erro para .../Django/mysite/templates/?

Tenho certeza sobre este, mas acho que eles precisam ser "globais" para o site.

astrognocci
fonte