django ข้อผิดพลาด MultiValueDictKeyError ฉันจะจัดการกับมันได้อย่างไร


174

ฉันพยายามบันทึกวัตถุในฐานข้อมูลของฉัน แต่มันมีMultiValueDictKeyErrorข้อผิดพลาดเกิดขึ้น

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

ฉันจะจัดการกับข้อยกเว้นนี้อย่างถูกต้องและจับได้อย่างไร

บรรทัดคือ

is_private = request.POST['is_private']

1
ความคิดที่ดีคือการแสดงให้เราเห็นข้อผิดพลาดทั้งหมดและการติดตาม ยังแสดงให้เราเห็นมากขึ้นของส่วนของรหัสที่เกิดข้อผิดพลาด
rzetterberg

1
ทุกคนสามารถอธิบายได้ว่าทำไมข้อผิดพลาดนี้เกิดขึ้นฉันเห็นข้อผิดพลาดนี้เมื่อฉันใช้ Modelviewset ที่แตกต่างกันในส่วนที่เหลือ django .....
Amrit

1
มันแปลว่าเรียบง่าย: ไม่มีรหัส 'is_private'!
ThePhi

คำตอบ:


282

ใช้getวิธีการของ MultiValueDict สิ่งนี้ยังปรากฏใน dicts มาตรฐานและเป็นวิธีการดึงค่าในขณะที่ให้ค่าเริ่มต้นหากไม่มีอยู่

is_private = request.POST.get('is_private', False)

โดยทั่วไปแล้ว

my_var = dict.get(<key>, <default>)

2
สิ่งนี้ให้ค่า None แต่ฉันกำลังส่งค่าใน POST: /
Jesus Almaral - Hackaprende

มันเป็นพฤติกรรมที่ถูกต้อง .. ช่องทำเครื่องหมายส่งcheckedเมื่อมีการตรวจสอบ แต่จะส่งnullถ้าไม่ได้ตรวจสอบ คุณสามารถตรวจสอบได้ในแผง "เครือข่าย" ของเครื่องมือ Chrome / Firefox DEV นั่นคือเหตุผลที่คุณตั้งค่าFalseเป็นค่าเริ่มต้น: ถ้ามีให้มันnull false
WesternGun

78

เลือกสิ่งที่ดีที่สุดสำหรับคุณ:

1

is_private = request.POST.get('is_private', False);

หากis_privateคีย์มีอยู่ในคำขอ POST is_privateตัวแปรจะเท่ากับถ้าไม่เช่นนั้นก็จะเท่ากับเท็จ

2

if 'is_private' in request.POST:
    is_private = request.POST['is_private']
else:
    is_private = False

3

from django.utils.datastructures import MultiValueDictKeyError
try:
    is_private = request.POST['is_private']
except MultiValueDictKeyError:
    is_private = False

12
ไม่สามารถแนะนำหมายเลข 3 ได้จริงๆ
โจ

6
ดูเหมือนว่าเป็นการละเมิดระบบยกเว้น ข้อยกเว้นควรสำหรับการจัดการพฤติกรรมพิเศษ (เช่นพฤติกรรมที่คุณรู้ว่าอาจเกิดขึ้นและต้องจัดการกับ แต่คุณไม่คาดหวังในโฟลว์โปรแกรมปกติ) ในกรณีนี้จะมีการโยนข้อยกเว้นและจับไปใน 50% ของการไหลของโปรแกรมที่เป็นไปได้ ที่เพิ่มเข้ามานั่นก็คือการชะลอความเร็ว ฉันไม่ทราบรายละเอียดว่ามันทำงานอย่างไรใน Python แต่ฉันจะจินตนาการว่า stack-trace ราคาแพงจะเกี่ยวข้อง
Joe

13
จาก django.utils.datastructures นำเข้า MultiValueDictKeyError
Akseli Palén

8
@Joe - ใน Python วิธีการนี้ค่อนข้างธรรมดา หากคุณตรวจพบข้อยกเว้นมันจะไม่สร้างสแต็คติดตามโดยอัตโนมัติ docs.python.org/2/glossary.html#term-eafp
bjudson

9
ไม่มีอะไรผิดปกติกับขั้นตอนที่ 3 เราเรียกมันว่าง่ายกว่าที่จะขอการให้อภัยมากกว่าการอนุญาต (EAFP) และเป็นรูปแบบการเข้ารหัสที่แนะนำใน Python โพสต์มากมายใน StackOverflow ได้กล่าวถึงเรื่องนี้
Bobort

12

คุณได้รับเพราะคุณกำลังพยายามรับกุญแจจากพจนานุกรมเมื่อไม่มีอยู่ คุณต้องทดสอบว่ามันอยู่ในนั้นก่อนหรือไม่

ลอง:

is_private = 'is_private' in request.POST

หรือ

is_private = 'is_private' in request.POST and request.POST['is_private']

ขึ้นอยู่กับค่าที่คุณใช้


5

ทำไมคุณไม่พยายามที่จะกำหนดis_privateในรูปแบบของคุณเป็นdefault=False?

class Foo(models.Models):
    is_private = models.BooleanField(default=False)

2
ที่จะไม่ป้องกันข้อผิดพลาดที่เขาได้รับการตรวจสอบ POST ด้วยตนเองสำหรับค่า
Apollo Data

4

สิ่งที่ต้องจำไว้ก็คือว่าrequest.POST['keyword']หมายถึงองค์ประกอบที่ระบุโดย html ที่ระบุแอตทริบิวต์namekeyword

ดังนั้นถ้าแบบฟอร์มของคุณคือ:

<form action="/login/" method="POST">
  <input type="text" name="keyword" placeholder="Search query">
  <input type="number" name="results" placeholder="Number of results">
</form>

จากนั้นrequest.POST['keyword']และrequest.POST['results']จะมีค่าขององค์ประกอบอินพุตkeywordและresultsตามลำดับ


1

ก่อนอื่นให้ตรวจสอบว่าวัตถุคำขอมีพารามิเตอร์คีย์ 'is_private' หรือไม่ กรณีส่วนใหญ่ของ MultiValueDictKeyError นี้เกิดขึ้นเนื่องจากมีคีย์หายไปในออบเจ็กต์คำขอคล้ายพจนานุกรม เนื่องจากพจนานุกรมเป็นคีย์ที่ไม่เรียงลำดับคู่ค่า“ ความทรงจำเชื่อมโยง” หรือ“ อาร์เรย์เชื่อมโยง”

ในคำอื่น ๆ request.GET หรือ request.POST เป็นวัตถุคล้ายพจนานุกรมที่มีพารามิเตอร์คำขอทั้งหมด นี่คือเฉพาะสำหรับ Django

เมธอด get () ส่งคืนค่าสำหรับคีย์ที่กำหนดหากคีย์อยู่ในพจนานุกรม ถ้าคีย์ไม่พร้อมใช้งานแล้วส่งกลับค่าเริ่มต้นไม่มี

คุณสามารถจัดการข้อผิดพลาดนี้ได้โดยใส่:

is_private = request.POST.get('is_private', False);

1

สำหรับฉันข้อผิดพลาดนี้เกิดขึ้นในโครงการ django ของฉันเพราะสิ่งต่อไปนี้:

  1. ฉันแทรกไฮเปอร์ลิงก์ใหม่ในหน้าแรกของฉัน HTML แสดงอยู่ในโฟลเดอร์แม่แบบของโครงการของฉันดังนี้:

    <input type="button" value="About" onclick="location.href='{% url 'about' %}'">

  2. ใน Views.py ฉันมีคำจำกัดความของการนับและเกี่ยวกับต่อไปนี้:

   def count(request):
           fulltext = request.GET['fulltext']
           wordlist = fulltext.split()
           worddict = {}
           for word in wordlist:
               if word in worddict:
                   worddict[word] += 1
               else:
                   worddict[word] = 1
                   worddict = sorted(worddict.items(), key = operator.itemgetter(1),reverse=True)
           return render(request,'count.html', 'fulltext':fulltext,'count':len(wordlist),'worddict'::worddict})

   def about(request): 
       return render(request,"about.html")
  1. ใน url.py ฉันมีรูปแบบ URL ต่อไปนี้:
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('',views.homepage,name="home"),
        path('eggs',views.eggs),
        path('count/',views.count,name="count"),
        path('about/',views.count,name="about"),
    ]

ที่สามารถเห็นได้ในหมายเลข 3 ด้านบนในรูปแบบ URL ล่าสุดฉันโทรไปยัง views.count อย่างไม่ถูกต้องในขณะที่ฉันต้องการเรียกใช้ views.about fulltext = request.GET['fulltext']ฟังก์ชั่นการนับบรรทัดนี้(ซึ่งถูกเรียกผิดเนื่องจากความผิดพลาดในรายการ urlpatterns) ของ views.py ทำให้เกิดข้อยกเว้นแบบหลายค่าคีย์

จากนั้นฉันเปลี่ยนรูปแบบ URL ล่าสุดเป็น url.py ให้เป็นรูปแบบที่ถูกต้องนั่นคือpath('about/',views.about,name="about")ทุกอย่างทำงานได้ดี

เห็นได้ชัดว่าโดยทั่วไปแล้วโปรแกรมเมอร์มือใหม่ใน django สามารถทำผิดพลาดได้ฉันทำผิดพลาดในการเรียกฟังก์ชั่นมุมมองอื่นสำหรับ url ซึ่งอาจคาดหวังว่าชุดพารามิเตอร์ที่แตกต่างกันหรือผ่านชุดของวัตถุต่าง ๆ ในการแสดงผล

หวังว่านี่จะช่วยโปรแกรมเมอร์ใหม่ให้กับ django

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