Django, tworząc niestandardową stronę błędu 500/404

105

Postępując zgodnie z samouczkiem znajdującym się tutaj , nie mogę utworzyć niestandardowej strony błędu 500 lub 404. Jeśli wpiszę zły adres URL, strona wyświetli domyślną stronę błędu. Czy jest coś, co powinienem sprawdzić, co uniemożliwiłoby wyświetlenie strony niestandardowej?

Katalogi plików:

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

w mysite / settings.py mam te włączone:

DEBUG = False
TEMPLATE_DEBUG = DEBUG

#....

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

w ramach 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'),
)

Mogę opublikować inny potrzebny kod, ale co powinienem zmienić, aby uzyskać niestandardową stronę błędu 500, jeśli używam złego adresu URL?

Edytować

ROZWIĄZANIE: Miałem dodatkowy

TEMPLATE_DIRS

w moim settings.py i to było przyczyną problemu

Zac
źródło
1
Debugowanie jest ustawione na False w moim kodzie
Zac,
To może pomóc ci stackoverflow.com/a/12180499/1628832
karthikr.
1
Znalazłem tę odpowiedź, szukając sposobu na stworzenie tylko niestandardowego szablonu i chciałem podzielić się trochę dokumentacją Django, która bardzo mi pomogła; docs.djangoproject.com/en/1.7/ref/views/ ...
Blackeagle52
Mój działał bez ustawienia template_dirs.
Programmingjoe,
1
Punkty za ironię, gdy link w pierwszej linii prowadzi do strony 404 Django. Prowadzi do strony z samouczkiem dla wersji Django, która chyba nie istnieje. Oto link do strony poradnika dla Django 2.0: docs.djangoproject.com/en/2.0/intro/tutorial03
andrewec

Odpowiedzi:

120

Pod swoim głównym views.pydodaj własną, niestandardową implementację następujących dwóch widoków i po prostu skonfiguruj szablony 404.html i 500.html z tym, co chcesz wyświetlić.

Dzięki temu rozwiązaniu nie trzeba dodawać żadnego niestandardowego kodu urls.py

Oto kod:

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

Aktualizacja

handler404i handler500są eksportowane zmienne konfiguracyjne ciągów Django znalezione w django/conf/urls/__init__.py. Dlatego powyższa konfiguracja działa.

Aby powyższa konfiguracja działała, należy zdefiniować następujące zmienne w swoim urls.pypliku i skierować wyeksportowane zmienne Django do ścieżki w języku Python, w której zdefiniowane są te widoki funkcjonalne Django, na przykład:

# project/urls.py

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

Aktualizacja dla Django 2.0

Podpisy dla widoków obsługi zostały zmienione w Django 2.0: https://docs.djangoproject.com/en/2.0/ref/views/#error-views

Jeśli używasz widoków jak powyżej, program handler404 zakończy się niepowodzeniem z komunikatem:

„funkcja handler404 () otrzymała nieoczekiwany argument słowa kluczowego„ wyjątek ””

W takim przypadku zmodyfikuj swoje widoki w ten sposób:

def handler404(request, exception, template_name="404.html"):
    response = render_to_response(template_name)
    response.status_code = 404
    return response
Aaron Lelevier
źródło
Wydawało mi się, że działa to całkiem nieźle, ale z jakiegoś powodu request.user wygląda dobrze w szablonie 404, ale wcale nie w szablonie 500 (i są prawie identyczne) - opublikowałem pytanie na ten temat tutaj: stackoverflow.com/ pytania / 26043211 /…
Gravity Grave
1
Kolejna rzecz, nad którą się zastanawiałem - co jeśli korzystasz z zaplecza administracyjnego i chcesz używać do tego oddzielnych szablonów? O ile mi wiadomo, admin nie ma pliku views.py do zastąpienia i umieszczenia tego fragmentu kodu.
Gravity Grave
11
@GravityGrave 500 templatenie wyrenderuje się, request.userponieważ zgłasza błąd serwera 500, więc serwer nie jest w stanie niczego obsłużyć.
Aaron Lelevier,
5
Nie działało dla mnie z django 1.9; (Może robię coś źle. Czy handler404 django jest zastrzeżoną nazwą? Skąd django wiedziałoby, że powinien wywołać dokładnie ten widok?
deathangel908
1
Zaktualizowałem odpowiedź na podstawie Twojego komentarza. Przepraszamy, że aktualizacja jest tak późna. Mam nadzieję, że to pomoże.
Aaron Lelevier
71

Oficjalna odpowiedź:

Oto link do oficjalnej dokumentacji na temat konfigurowania niestandardowych widoków błędów:

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

Mówi, aby dodać takie linie w swoim URLconf (ustawienie ich gdziekolwiek indziej nie przyniesie efektu):

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'

Możesz również dostosować widok błędów CSRF, modyfikując ustawienie CSRF_FAILURE_VIEW.

Domyślne programy obsługi błędów:

Warto czytać dokumentację z obsługą domyślne błędów page_not_found, server_error, permission_deniedi bad_request. Domyślnie oni korzystać z tych szablonów, czy mogą je znaleźć odpowiednio: 404.html, 500.html, 403.html, i 400.html.

Więc jeśli wszystko, co chcesz zrobić, to stworzyć ładne strony błędów, po prostu utwórz te pliki w TEMPLATE_DIRSkatalogu, nie musisz w ogóle edytować URLConf. Przeczytaj dokumentację, aby zobaczyć, które zmienne kontekstu są dostępne.

W Django 1.10 i nowszych domyślny widok błędów CSRF używa szablonu 403_csrf.html.

Mam cię:

Nie zapominaj, że DEBUGmusi być ustawione na False, aby te działały, w przeciwnym razie zostaną użyte normalne procedury obsługi debugowania.

Flimm
źródło
1
Dodałem, ale to nie działa. Dodano handler404 i inne wskazujące na właściwe miejsca w moich widokach, ale to nie działa, nadal widzę domyślny 404. I tak, jestem w trybie Debug False i używam 1.9
KhoPhi
Użycie Django 1.9 i po prostu dodanie szablonów 500.html itp. Powoduje wyświetlenie ich zamiast standardowych stron. Niezłe, łatwe rozwiązanie.
curtisp
2
Gotcha mi pomogła. Zadziałało, wprowadzając te zmiany w moim settings.py, ustawiając DEBUG = False i ALLOWED_HOSTS = ['0.0.0.0'], aby akceptować żądanie http od dowolnego klienta.
shaffooo
1
Na wszelki wypadek, gdyby ktoś jeszcze się zastanawiał, gdzie na ziemi jest URLconf, oto on
Arthur Tarasov
38

Dodaj te linie do 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'

# ...

i zaimplementuj nasze niestandardowe widoki w 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
źródło
5
Dlaczego miałbyś importować handler400tylko po to, aby go nadpisać handler400 = 'myapp.views.bad_request'?
Flimm
5
Nie musisz tutaj importować programów obsługi, aby je zastąpić.
funkotron
1
Nie powinieneś używać render_to_response. Z dokumentacji: „nie jest zalecane i prawdopodobnie zostanie wycofane w przyszłości”.
Timmy O'Mahony
W przypadku Django 1.10, render_to_responsektóre będzie przestarzałe, zobacz następujące (użyj renderzamiast tego): stackoverflow.com/questions/44228397/…
mrdaliri
21

Ze strony, do której się odwołałeś:

Kiedy podniesiesz Http404 z poziomu widoku, Django załaduje specjalny widok poświęcony obsłudze błędów 404. Znajduje ją, szukając zmiennej handler404 w twoim głównym URLconf (i tylko w twoim głównym URLconf; ustawienie handler404 gdziekolwiek indziej nie odniesie skutku), która jest łańcuchem w składni kropkowanej Pythona - tym samym formacie, którego używają normalne wywołania zwrotne URLconf. Sam widok 404 nie ma nic specjalnego: to tylko normalny widok.

Więc uważam, że musisz dodać coś takiego do swojego urls.py:

handler404 = 'views.my_404_view'

i podobne dla handler500.

Mike Pelley
źródło
Jak to wygląda, Mike? Dzisiaj jest mój pierwszy dzień używania Django i nadal trzymam się lin
Zac,
2
@JimRilye Musisz dodać odpowiednią funkcję 500 do swoich widoków, a następnie odwołać się do niej za pomocą tej zmiennej. Tak więc nad urlpatterns = ...linią dodaj linię z napisem handler500 = 'views.handle500', a następnie dodaj def handle500(request):do swojego views.py, który wyświetla twój 500.html.
Mike Pelley,
18

Jeśli wszystko, czego potrzebujesz, to pokazać niestandardowe strony, które mają kilka wymyślnych komunikatów o błędach dla Twojej witryny, kiedy DEBUG = False, dodaj dwa szablony o nazwach 404.html i 500.html do katalogu szablonów, a te niestandardowe strony będą automatycznie pobierane po 404 lub 500 jest podniesiony.

Krishna G Nair
źródło
1
To działa, po prostu upewnij się, że masz coś takiego: 'DIRS': [os.path.join(BASE_DIR, '<project_name>/templates')]na liście SZABLONY w settings.py.
eric
12

W Django 2. * możesz użyć tej konstrukcji w views.py

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

W settings.py

DEBUG = False

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

if DEBUG is True:
    ALLOWED_HOSTS = []

W urls.py

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

Zwykle tworzę default_app i obsługuję błędy całej witryny, w tym procesory kontekstu.

Legowisko
źródło
Pracuj dla mnie. Ale co to jest exception?
zeleven
Zgodnie z linkiem do dokumentacji: docs.djangoproject.com/en/2.1/ref/urls/… . Jest napisane: upewnij się, że przewodnik akceptuje argumenty żądań i wyjątków
Alouani Younes
1
Pracował dla mnie w Django 3.0 . Ale co to jest locals()? Plik pokazuje tylko pass.
enchance
9

settings.py:

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

i po prostu dodaj swoje strony 404.htmli 500.htmldo folderu szablonów. usuń 404.htmli 500.htmlz szablonów w aplikacji ankiet.

Rakesh babu
źródło
Jak korzystać z wiadomości raise Http404('msg'): stackoverflow.com/a/37109914/895245 {{ request_path }} jest również dostępna.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
TEMPLATE_DEBUG został usunięty z django2 docs.quantifiedcode.com/python-anti-patterns/django/1.8/…
Steve W
7

Zrób błąd, na stronie błędu dowiedz się, skąd django ładuje szablony, mam na myśli stos ścieżek. W podstawowym katalogu template_dir dodaj te strony html 500.html , 404.html . W przypadku wystąpienia tych błędów odpowiednie pliki szablonów zostaną automatycznie załadowane.

Możesz także dodać strony dla innych kodów błędów, takich jak 400 i 403 .

Mam nadzieję, że to pomoże !!!

allsyed
źródło
6

W Django 3.xzaakceptowana odpowiedź nie zadziała, ponieważ render_to_responsezostała całkowicie usunięta, a także wprowadzono więcej zmian od wersji, dla której działała zaakceptowana odpowiedź.

Są tam również inne odpowiedzi, ale przedstawiam nieco bardziej przejrzystą odpowiedź:

W głównym urls.pypliku:

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

W yourapp/views.pypliku:

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

Upewnij się, że zaimportowałeś render()do yourapp/views.pypliku:

from django.shortcuts import render

Uwaga dodatkowa: render_to_response()został 2.xuznany za przestarzały w Django i został całkowicie usunięty w wersji 3.x.

Rehmat
źródło
5

Jako jeden wiersz (dla strony ogólnej 404):

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
źródło
1
A gdzie go używać?
Sami
5

Nie jest wymagany żaden dodatkowy widok. https://docs.djangoproject.com/en/3.0/ref/views/

Po prostu umieść pliki błędów w katalogu głównym szablonów

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

Powinien również używać strony błędu, gdy debugowanie jest fałszywe

Anuj TBE
źródło
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' 

Działa to na django 2.0

Pamiętaj, aby umieścić swój niestandardowy 404.htmlplik w folderze szablonów aplikacji.

ENDEESA
źródło
4

Django 3.0

tutaj jest link jak dostosować widoki błędów

tutaj jest link jak renderować widok

w urls.py(głównym folderze projektu) umieść:

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'

aw tej aplikacji ( my_app_name) umieść 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", {})

UWAGA: error/404.htmlto ścieżka, jeśli umieścisz pliki w folderze szablonów projektów (nie aplikacji)templates/errors/404.html więc umieść pliki tam, gdzie chcesz, i napisz właściwą ścieżkę.

UWAGA 2: Jeśli po przeładowaniu strony nadal widzisz stary szablon, zmień go settings.py DEBUG=True, zapisz, a następnie ponownie do False(aby zrestartować serwer i zebrać nowe pliki).

elano7
źródło
Dodatkowa uwaga: jeśli korzystasz z DEUB=Falseplików statycznych, mogą nie być obsługiwane, przez co nie możesz wyświetlić podglądu zmian niestandardowego szablonu błędu. Użyj, ./manage.py runserver --insecureby i tak zmusić django do obsługi.
Rob
3

Spróbuj przenieść szablony błędów do .../Django/mysite/templates/?

Jestem pewien co do tego, ale myślę, że muszą one być „globalne” dla witryny.

astrognocci
źródło