Django สร้างหน้าข้อผิดพลาด 500/404 ที่กำหนดเอง


107

ตามบทช่วยสอนที่พบที่นี่ฉันไม่สามารถสร้างหน้าข้อผิดพลาด 500 หรือ 404 ที่กำหนดเองได้ หากฉันพิมพ์ URL ที่ไม่ถูกต้องหน้านั้นจะแสดงหน้าข้อผิดพลาดเริ่มต้นให้ฉัน มีอะไรที่ฉันควรตรวจสอบเพื่อป้องกันไม่ให้เพจที่กำหนดเองแสดงขึ้นมา?

ไดเร็กทอรีไฟล์:

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

ภายใน mysite / settings.py ฉันได้เปิดใช้งานสิ่งเหล่านี้:

DEBUG = False
TEMPLATE_DEBUG = DEBUG

#....

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

ภายใน 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'),
)

ฉันสามารถโพสต์รหัสอื่น ๆ ที่จำเป็นได้ แต่ฉันควรเปลี่ยนอะไรเพื่อให้ได้หน้าแสดงข้อผิดพลาด 500 ที่กำหนดเองหากฉันใช้ URL ที่ไม่ถูกต้อง

แก้ไข

วิธีแก้ปัญหา: ฉันมีเพิ่มเติม

TEMPLATE_DIRS

ภายใน settings.py ของฉันและนั่นเป็นสาเหตุของปัญหา


1
Debug ถูกตั้งค่าเป็น False ในรหัสของฉัน
Zac

สิ่งนี้สามารถช่วยคุณได้stackoverflow.com/a/12180499/1628832
karthikr

1
พบคำตอบนี้ในขณะที่กำลังมองหาวิธีสร้างเฉพาะเทมเพลตที่กำหนดเองและฉันต้องการแบ่งปันเอกสาร Django ซึ่งช่วยฉันได้มาก docs.djangoproject.com/th/1.7/ref/views/…
Blackeagle52

เหมืองทำงานโดยไม่มีการตั้งค่า template_dirs
Programmingjoe

1
จุดประชดเมื่อลิงก์ในบรรทัดแรกนำไปสู่หน้า 404 ของ Django นำไปสู่หน้าการสอนสำหรับ Django เวอร์ชันที่ฉันคิดว่าไม่มีอยู่จริง นี่คือลิงค์ไปยังหน้าบทช่วยสอนสำหรับ Django 2.0: docs.djangoproject.com/en/2.0/intro/tutorial03
andrewec

คำตอบ:


123

ภายใต้หลักของคุณให้views.pyเพิ่มการใช้งานสองมุมมองต่อไปนี้ที่กำหนดเองของคุณเองและเพียงตั้งค่าเทมเพลต404.htmlและ500.htmlด้วยสิ่งที่คุณต้องการแสดง

ด้วยโซลูชันนี้ไม่จำเป็นต้องเพิ่มโค้ดที่กำหนดเอง urls.py

นี่คือรหัส:

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

อัปเดต

handler404และhandler500ส่งออกตัวแปรการกำหนดค่าสตริง Django ที่พบในdjango/conf/urls/__init__.py. นั่นคือเหตุผลที่การกำหนดค่าข้างต้นใช้งานได้

เพื่อให้การกำหนดค่าข้างต้นทำงานคุณควรกำหนดตัวแปรต่อไปนี้ในurls.pyไฟล์ของคุณและชี้ตัวแปร Django ที่ส่งออกไปยังเส้นทาง Python ของสตริงที่กำหนดมุมมองฟังก์ชัน Django เหล่านี้ดังนี้

# project/urls.py

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

อัปเดตสำหรับ Django 2.0

ลายเซ็นสำหรับมุมมองตัวจัดการมีการเปลี่ยนแปลงใน Django 2.0: https://docs.djangoproject.com/en/2.0/ref/views/#error-views

หากคุณใช้มุมมองดังกล่าวข้างต้น handler404 จะล้มเหลวด้วยข้อความ:

"handler404 () มีอาร์กิวเมนต์คำหลัก" ข้อยกเว้น "ที่ไม่คาดคิด"

ในกรณีดังกล่าวให้ปรับเปลี่ยนมุมมองของคุณดังนี้:

def handler404(request, exception, template_name="404.html"):
    response = render_to_response(template_name)
    response.status_code = 404
    return response

ดูเหมือนว่าจะทำงานได้ดีสำหรับฉัน แต่ด้วยเหตุผลบางประการการร้องขอผู้ใช้ปรากฏว่าดีในเทมเพลต 404 แต่ไม่ปรากฏเลยในเทมเพลต 500 (และเกือบจะเหมือนกัน) - โพสต์คำถามไว้ที่นี่: stackoverflow.com/ คำถาม / 26043211 / …
Gravity Grave

1
อีกสิ่งหนึ่งที่ฉันสงสัย - จะเกิดอะไรขึ้นถ้าคุณใช้แบ็กเอนด์ผู้ดูแลระบบและต้องการใช้เทมเพลตแยกต่างหากสำหรับสิ่งเหล่านั้น สำหรับความรู้ของฉันผู้ดูแลระบบไม่มี views.py ที่จะแทนที่และใส่บิตของโค้ดนี้
Gravity Grave

11
@GravityGrave 500 templateจะไม่แสดงผลrequest.userเนื่องจากมีการรายงานข้อผิดพลาด 500 เซิร์ฟเวอร์ดังนั้นเซิร์ฟเวอร์จึงไม่สามารถให้บริการอะไรได้
Aaron Lelevier

5
ไม่ได้ทำงานให้ฉันด้วย Django 1.9 (บางทีฉันทำอะไรผิดพลาดคือ handler404 django ชื่อที่สงวนไว้อย่างไรจะ django รู้ว่ามันควรจะเรียกว่าที่มุมมอง.?
deathangel908

1
ฉันอัปเดตคำตอบตามความคิดเห็นของคุณ ขออภัยที่การอัปเดตล่าช้ามาก ฉันหวังว่าสิ่งนี้จะช่วยได้
Aaron Lelevier

73

คำตอบอย่างเป็นทางการ:

นี่คือลิงค์ไปยังเอกสารอย่างเป็นทางการเกี่ยวกับวิธีตั้งค่ามุมมองข้อผิดพลาดที่กำหนดเอง:

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

มันบอกว่าให้เพิ่มบรรทัดแบบนี้ใน URLconf ของคุณ (ตั้งค่าไว้ที่อื่นจะไม่มีผล)

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'

นอกจากนี้คุณยังสามารถปรับแต่งมุมมองข้อผิดพลาด CSRF CSRF_FAILURE_VIEWโดยการปรับเปลี่ยนการตั้งค่า

ตัวจัดการข้อผิดพลาดเริ่มต้น:

มันคุ้มค่าที่อ่านเอกสารของการเริ่มต้นการจัดการข้อผิดพลาด, page_not_found, server_error, และpermission_denied bad_requestโดยค่าเริ่มต้นที่พวกเขาใช้แม่แบบเหล่านี้หากพวกเขาสามารถพบพวกเขาตามลำดับ: 404.html, 500.html, และ403.html400.html

ดังนั้นหากสิ่งที่คุณต้องการทำคือสร้างหน้าแสดงข้อผิดพลาดเพียงสร้างไฟล์เหล่านั้นในTEMPLATE_DIRSไดเร็กทอรีคุณไม่จำเป็นต้องแก้ไข URLConf เลย อ่านเอกสารประกอบเพื่อดูว่ามีตัวแปรบริบทใดบ้าง

ใน Django 1.10 และต่อมาดูข้อผิดพลาด CSRF 403_csrf.htmlเริ่มต้นใช้แม่แบบ

Gotcha:

อย่าลืมว่าDEBUGต้องตั้งค่าเป็น False เพื่อให้สิ่งเหล่านี้ทำงานได้มิฉะนั้นจะใช้ตัวจัดการการดีบักปกติ


1
ฉันเพิ่ม แต่มันไม่ได้ผล เพิ่ม handler404 และอื่น ๆ ที่ชี้ไปยังตำแหน่งที่ถูกต้องในมุมมองของฉัน แต่มันใช้ไม่ได้ยังคงเห็นค่าเริ่มต้น 404 และใช่ฉันอยู่ในโหมด Debug False และใช้ 1.9
KhoPhi

การใช้ Django 1.9 และเพิ่มเทมเพลตอื่น ๆ อีก 500.html จะแสดงแทนเพจมาตรฐาน แก้ไขง่ายดี
curtisp

2
Gotchaช่วยฉันด้วย มันทำงานได้โดยทำการเปลี่ยนแปลงเหล่านี้ใน settings.py ของฉันตั้งค่า DEBUG = False และ ALLOWED_HOSTS = ['0.0.0.0'] เพื่อยอมรับคำขอ http จากไคลเอนต์ใด ๆ
shaffooo

1
ในกรณีที่คนอื่นสงสัยว่า URLconf อยู่ที่ไหนในโลกนี่คือ
Arthur Tarasov

@ArthurTarasov ใช่จะดีกว่าถ้าอ้างอิงไฟล์ urls.py ควบคู่ไปด้วยฮ่า ๆ
Zack Plauché

42

เพิ่มบรรทัดเหล่านี้ใน 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'

# ...

และใช้มุมมองที่กำหนดเองของเราใน 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

# ...

6
จะนำเข้าhandler400มาเพื่อเขียนทับด้วยhandler400 = 'myapp.views.bad_request'ทำไม?
Flimm


5
คุณไม่จำเป็นต้องนำเข้าเครื่องจัดการที่นี่เพื่อที่จะลบล้างพวกเขา
funkotron

1
คุณไม่ควรใช้render_to_response. จากเอกสาร: "ไม่แนะนำและมีแนวโน้มที่จะเลิกใช้งานในอนาคต"
Timmy O'Mahony

สำหรับ Django 1.10 ที่render_to_responseกำลังจะเลิกใช้งานโปรดดูด้านrender
ล่าง

21

จากหน้าที่คุณอ้างถึง:

เมื่อคุณเพิ่ม Http404 จากภายในมุมมอง Django จะโหลดมุมมองพิเศษสำหรับจัดการข้อผิดพลาด 404 พบโดยค้นหาตัวแปร handler404 ใน root URLconf ของคุณ (และเฉพาะใน root URLconf ของคุณเท่านั้นการตั้งค่า handler404 ที่อื่นจะไม่มีผล) ซึ่งเป็นสตริงใน Python dotted syntax ซึ่งเป็นรูปแบบเดียวกับที่การเรียกกลับ URLconf ปกติใช้ มุมมอง 404 นั้นไม่มีอะไรพิเศษ แต่เป็นเพียงมุมมองปกติ

ดังนั้นฉันเชื่อว่าคุณต้องเพิ่มสิ่งนี้ใน urls.py ของคุณ:

handler404 = 'views.my_404_view'

และคล้ายกันสำหรับ handler500


ไมค์มองยังไง? วันนี้เป็นวันแรกของฉันที่ใช้ Django และฉันยังคงแขวนอยู่บนเชือก
Zac

2
@JimRilye คุณจะต้องเพิ่มฟังก์ชัน 500 ที่เหมาะสมในมุมมองของคุณจากนั้นอ้างอิงกับตัวแปรนั้น ดังนั้นเหนือurlpatterns = ...บรรทัดของคุณให้เพิ่มบรรทัดที่ระบุว่าhandler500 = 'views.handle500'แล้วเพิ่มdef handle500(request):ใน views.py ของคุณที่แสดง 500.html ของคุณ
Mike Pelley

19

หากคุณต้องการเพียงแค่แสดงหน้าเว็บแบบกำหนดเองซึ่งมีข้อความแสดงข้อผิดพลาดบางอย่างสำหรับไซต์ของคุณเมื่อใดDEBUG = Falseให้เพิ่มเทมเพลตสองรายการชื่อ 404.html และ 500.html ในไดเรกทอรีเทมเพลตของคุณและจะรับหน้าเว็บที่กำหนดเองนี้โดยอัตโนมัติเมื่อเป็น 404 หรือ 500 ถูกยกขึ้น


1
วิธีนี้ใช้งานได้เพียงตรวจสอบให้แน่ใจว่าคุณมีสิ่งที่ต้องการ: 'DIRS': [os.path.join(BASE_DIR, '<project_name>/templates')]ในรายการเทมเพลตของคุณในsettings.py.
eric

13

ในDjango 2 *คุณสามารถใช้โครงสร้างนี้ในviews.py

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

ในsettings.py

DEBUG = False

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

if DEBUG is True:
    ALLOWED_HOSTS = []

ในurls.py

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

โดยปกติฉันสร้างdefault_appและจัดการข้อผิดพลาดทั่วทั้งไซต์ตัวประมวลผลบริบทในนั้น


ทำงานให้ฉัน แต่คือexceptionอะไร?
zeleven

ตามลิงค์เอกสาร: docs.djangoproject.com/en/2.1/ref/urls/… . มันเขียน: ตรวจสอบให้แน่ใจว่าตัวจัดการยอมรับคำขอและข้อโต้แย้งข้อยกเว้น
Alouani Younes

1
ทำงานสำหรับฉันในDjango 3.0 แต่คือlocals()อะไร? passไฟล์ที่แสดงให้เห็นเท่านั้น
enchance

11

settings.py:

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

และเพียงแค่เพิ่ม404.htmlและ500.htmlเพจของคุณในโฟลเดอร์เทมเพลต ลบ404.htmlและออก500.htmlจากเทมเพลตในแอพโพล


วิธีใช้ข้อความของraise Http404('msg'): stackoverflow.com/a/37109914/895245 {{ request_path }}ก็มี
Ciro Santilli 郝海东冠状病六四事件法轮功

TEMPLATE_DEBUG ถูกลบออกจาก django2 docs.quantifiedcode.com/python-anti-patterns/django/1.8/…
Steve W

8

Django 3.0

นี่คือลิงค์วิธีปรับแต่งมุมมองข้อผิดพลาด

นี่คือลิงค์วิธีการแสดงผลมุมมอง

ในurls.py(รายการหลักในโฟลเดอร์โครงการ) ให้ใส่:

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'

และในแอพนั้น ( my_app_name) ใส่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", {})

หมายเหตุ: error/404.htmlเป็นเส้นทางหากคุณวางไฟล์ลงในโฟลเดอร์เทมเพลตโปรเจ็กต์ (ไม่ใช่แอพ) templates/errors/404.htmlดังนั้นโปรดวางไฟล์ในตำแหน่งที่คุณต้องการและเขียนเส้นทางที่ถูกต้อง

หมายเหตุ 2: หลังจากโหลดหน้าซ้ำหากคุณยังคงเห็นเทมเพลตเก่าให้เปลี่ยนsettings.py DEBUG=Trueบันทึกและจากนั้นอีกครั้งเป็นFalse(เพื่อรีสตาร์ทเซิร์ฟเวอร์และรวบรวมไฟล์ใหม่)


หมายเหตุเพิ่มเติม: หากคุณกำลังเรียกใช้DEUB=Falseไฟล์คงที่ของคุณอาจไม่ได้รับการให้บริการทำให้คุณไม่สามารถดูตัวอย่างการเปลี่ยนแปลงเทมเพลตข้อผิดพลาดที่กำหนดเองได้ ใช้./manage.py runserver --insecureเพื่อบังคับให้ django ให้บริการต่อไป
Rob

อธิบายได้ดีมาก!
Siva-Dev-Wizard

7

สร้างข้อผิดพลาดในหน้าข้อผิดพลาดค้นหาว่า django กำลังโหลดเทมเพลตจากที่ใดฉันหมายถึงพา ธ สแต็กในtemplate_dirพื้นฐานเพิ่มหน้า html เหล่านี้500.html , 404.html 404.htmlเมื่อเกิดข้อผิดพลาดเหล่านี้ไฟล์เทมเพลตตามลำดับจะถูกโหลดโดยอัตโนมัติ

คุณสามารถเพิ่มหน้ารหัสข้อผิดพลาดอื่น ๆ มากเกินไปเช่น400และ403

หวังว่าจะช่วยได้ !!!


7

ใน Django 3.xคำตอบที่ได้รับการยอมรับจะไม่ทำงานเนื่องจากrender_to_responseถูกลบออกอย่างสมบูรณ์และมีการเปลี่ยนแปลงเพิ่มเติมบางอย่างเนื่องจากเวอร์ชันที่คำตอบที่ยอมรับใช้งานได้

คำตอบอื่น ๆ ก็มีเช่นกัน แต่ฉันกำลังนำเสนอคำตอบที่สะอาดกว่าเล็กน้อย:

ในurls.pyไฟล์หลักของคุณ:

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

ในyourapp/views.pyไฟล์:

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

ตรวจสอบให้แน่ใจว่าคุณได้นำเข้าrender()ในyourapp/views.pyไฟล์:

from django.shortcuts import render

หมายเหตุด้านข้าง: render_to_response()เลิกใช้แล้วใน Django 2.xและได้ถูกลบออกอย่างสมบูรณ์ใน3.xรูปแบบ


6

ไม่จำเป็นต้องมีมุมมองเพิ่มเติม https://docs.djangoproject.com/en/3.0/ref/views/

เพียงใส่ไฟล์ข้อผิดพลาดในไดเรกทอรีรากของเทมเพลต

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

และควรใช้หน้าข้อผิดพลาดของคุณเมื่อการดีบักเป็นเท็จ


5

เป็นหนึ่งบรรทัดเดียว (สำหรับหน้าทั่วไป 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)

1
และใช้ที่ไหน?
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' 

สิ่งนี้ใช้ได้กับ django 2.0

อย่าลืมรวมแบบกำหนดเองของคุณ404.htmlไว้ในโฟลเดอร์เทมเพลตของแอป


3

ลองย้ายเทมเพลตข้อผิดพลาดของคุณไปที่.../Django/mysite/templates/?

ฉันทราบดีเกี่ยวกับเรื่องนี้ แต่ฉันคิดว่าสิ่งเหล่านี้จำเป็นต้อง "ทั่วโลก" สำหรับเว็บไซต์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.