django - เหตุใดวัตถุ request.POST จึงไม่เปลี่ยนรูป


110

ตามที่ชื่อถามว่าทำไมพวก Django ถึงตัดสินใจที่จะดำเนินการตามคำขอวัตถุ POST พร้อมแบบสอบถาม (ซึ่งในทางกลับกันทำให้ทุกอย่างไม่เปลี่ยนรูป?)

ฉันรู้ว่าคุณสามารถเปลี่ยนมันได้โดยการทำสำเนาข้อมูลโพสต์

post = request.POST.copy()

แต่ทำไมทำแบบนี้? แน่นอนว่ามันจะง่ายกว่าเพียงแค่ยอมให้สิ่งนั้นเปลี่ยนแปลงได้หรือไม่? หรือมีการใช้เพื่อเหตุผลอื่นด้วยซึ่งอาจทำให้เกิดปัญหา?


1
ทำไมคุณถึงต้องการให้มันไม่แน่นอน? คุณสามารถนำข้อมูลจากข้อมูลนั้นมาใช้ / แก้ไขได้ในมุมมองของคุณ ด้วยการเพิ่มข้อมูลเข้าไปคุณสามารถสร้างการแสดงผลที่request.POSTถูกส่งโดยมีข้อมูลมากกว่าที่เป็นจริง
Simeon Visser

11
ไม่ใช่ว่าฉันต้องการให้มันกลายพันธุ์ ไม่ต้องพูดมากกว่านี้ฉันอยากให้ไอศกรีมเย็น ๆ ในกรณีของไอศกรีมถ้าไม่เย็นมันจะละลายแล้วคุณจะโดนด่าว่าทำเละเทะ แต่ด้วยการร้องขอวัตถุ POST ... ฉันหมายความว่าถ้าฉันจะทำผิดรหัสของฉันฉันจะทำให้มันเสียหาย ฉันไม่ทราบว่ามีนักพัฒนาเฉพาะถิ่นเพิ่มข้อมูลไปยังออบเจ็กต์ POST และก่อให้เกิดปัญหาดังนั้นจึงดูเหมือนเป็นเรื่องแปลกที่กำหนดเป้าหมายเพื่อ "แก้ไข"
bharal

คำถามที่ดี; ไม่เคยคิดเลยจริงๆ
Burhan Khalid

1
สิ่งนี้เกิดขึ้นเป็นระยะ ๆ สำหรับฉันเนื่องจากบางครั้งลูกค้าของฉันส่งข้อมูล JSON (ไม่แน่นอน) และบางครั้งข้อความ URL ฟอร์มเข้ารหัส (ไม่เปลี่ยนรูป)
owenfi

2
สำหรับผู้ที่ไม่ใช้ภาษาอังกฤษ "mutify" ไม่ใช่คำ - วลีที่ถูกต้องคือ "you can mutate it" หรือ "you can modified it" นอกจากนี้ยังไม่จำเป็นต้องกำหนดเพศให้กับนักพัฒนา - คุณสามารถใช้ "Django team" หรือ "core devs" แทน "guys" ได้
alexmuller

คำตอบ:


131

มันเป็นเรื่องลึกลับใช่มั้ย? ทฤษฎีที่เป็นไปได้อย่างผิวเผินหลายประการกลับกลายเป็นสิ่งที่ผิดในการตรวจสอบ:

  1. เพื่อให้POSTวัตถุไม่ต้องใช้วิธีการกลายพันธุ์? ไม่มีที่: POSTวัตถุอยู่ในdjango.http.QueryDictระดับซึ่งการดำเนินการชุดเต็มของวิธีการกลายพันธุ์รวมทั้ง__setitem__, __delitem__, และpop clearมันใช้การไม่เปลี่ยนรูปโดยการตรวจสอบแฟล็กเมื่อคุณเรียกใช้วิธีการกลายพันธุ์อย่างใดอย่างหนึ่ง และเมื่อคุณเรียกใช้copyเมธอดนี้คุณจะได้รับQueryDictอินสแตนซ์อื่นพร้อมกับแฟล็กที่ไม่แน่นอนที่เปิดอยู่

  2. เพื่อการปรับปรุงประสิทธิภาพ? ไม่: QueryDictคลาสจะไม่ได้รับประโยชน์ด้านประสิทธิภาพเมื่อปิดแฟล็กที่เปลี่ยนแปลงได้

  3. เพื่อให้POSTวัตถุสามารถใช้เป็นคีย์พจนานุกรมได้? ไม่: QueryDictไม่สามารถล้างวัตถุได้

  4. เพื่อให้POSTสามารถสร้างข้อมูลได้อย่างเฉื่อยชา (โดยไม่ต้องอ่านคำตอบทั้งหมด) ตามที่อ้างไว้ที่นี่ ? ฉันไม่เห็นหลักฐานเกี่ยวกับเรื่องนี้ในโค้ดเท่าที่ฉันสามารถบอกได้ว่าคำตอบทั้งหมดจะถูกอ่านเสมอไม่ว่าจะโดยตรงหรือผ่านทางMultiPartParserสำหรับmultipartการตอบกลับ

  5. เพื่อป้องกันข้อผิดพลาดในการเขียนโปรแกรม? ฉันเคยเห็นการอ้างสิทธิ์นี้ แต่ฉันไม่เคยเห็นคำอธิบายที่ดีว่าข้อผิดพลาดเหล่านี้คืออะไรและความไม่เปลี่ยนรูปสามารถป้องกันคุณจากข้อผิดพลาดเหล่านี้ได้อย่างไร

ไม่ว่าในกรณีใด ๆPOSTจะไม่เปลี่ยนรูปเสมอไป : เมื่อการตอบสนองเป็นmultipartเช่นนั้นPOSTจะไม่แน่นอน สิ่งนี้ดูเหมือนจะทำให้ kibosh อยู่บนทฤษฎีส่วนใหญ่ที่คุณอาจคิด (เว้นแต่พฤติกรรมนี้เป็นการกำกับดูแล)

โดยสรุปฉันไม่เห็นเหตุผลที่ชัดเจนใน Django สำหรับPOSTวัตถุที่ไม่เปลี่ยนรูปสำหรับmultipartการร้องขอที่ไม่ใช่


ฉันสังเกตเห็นขอบขรุขระแบบนี้ใน Django ต้องทำให้ใครบางคนเข้าใจตรงกันในบางประเด็น
Dan Passaro

2
ฉันพบสิ่งนี้ในคำตอบ Stack อื่น: "และต้องไม่เปลี่ยนรูปจึงจะสามารถสร้างได้อย่างเกียจคร้านการคัดลอกบังคับให้รับข้อมูล POST ทั้งหมดจนกว่าสำเนาอาจไม่สามารถดึงข้อมูลทั้งหมดได้นอกจากนี้สำหรับ WSGI แบบมัลติเธรด เซิร์ฟเวอร์ทำงานได้ดีพอสมควรจะเป็นประโยชน์หากไม่เปลี่ยนรูป "
Seaux

12
@ คุณไม่ควรอ่าน SO คำตอบเมื่อคุณตั้งใจที่จะแสดงความคิดเห็นเกี่ยวกับพวกเขา ;-)
Chris Wesseling

3
@ChrisWesseling ฉันเห็นสิ่งที่คุณทำที่นั่น
Seaux

2
ยิ่งไปกว่านั้นแบบสอบถามไม่แน่นอนเมื่อฉันส่งคำขอฟ้องไคลเอนต์ทดสอบ django
user1158559

82

หากคำขอดังกล่าวเป็นผลมาจาก Django formส่งแล้วมันเป็นที่เหมาะสมสำหรับการโพสต์เป็นimmutableเพื่อความสมบูรณ์ของข้อมูลระหว่างรูปแบบการส่งและแบบฟอร์มการตรวจสอบ อย่างไรก็ตามหากคำขอไม่ได้ส่งผ่านการformส่งDjango แสดงว่า POST mutableไม่มีการตรวจสอบแบบฟอร์ม

คุณสามารถทำสิ่งนี้ได้ตลอดเวลา: (ตามความคิดเห็นของ @ leo-the-manic )

#  .....
mutable = request.POST._mutable
request.POST._mutable = True
request.POST['some_data'] = 'test data'
request.POST._mutable = mutable
# ......

3
@ JoshK: ฉันเดาว่าผู้แสดงความคิดเห็นต้องการทำให้ POST ไม่แน่นอนและข้อมูลโค้ดในคำตอบนี้ช่วยได้
ShreevatsaR

คุณสามารถเพิ่มคีย์ใหม่ค่า แต่ไม่สามารถเปลี่ยนแปลงข้อมูลที่มีอยู่ได้
Vamsidhar Muggulla

ดี. และฉันแน่ใจว่าใครก็ตามที่ใช้รหัสนี้รู้ว่าเขากำลังทำอะไรอยู่
John Pang

@VamsidharMuggulla ทั้งการเพิ่มและการเปลี่ยนแปลงเป็นไปได้ แม้กระทั่งการลบก็สามารถทำได้
Antony Hatchkins

5

อัปเดต :

Gareth Rees พูดถูกว่าจุด 1 & 3 ไม่ถูกต้องในกรณีนี้ แม้ว่าฉันคิดว่าจุดที่ 2 และ 4 ยังใช้ได้ดังนั้นฉันจะทิ้งวิทยานิพนธ์ไว้ที่นี่

(ฉันสังเกตว่าrequest.POSTวัตถุของทั้ง Pyramid (Pylon) และ Django เป็นรูปแบบบางอย่างMultiDictดังนั้นอาจเป็นวิธีปฏิบัติทั่วไปมากกว่าการทำให้request.POSTไม่เปลี่ยนรูป)


ฉันไม่สามารถพูดแทนพวก Django ได้แม้ว่าสำหรับฉันแล้วมันอาจจะเป็นเพราะเหตุผลเหล่านี้:

  1. การแสดง . วัตถุที่ไม่เปลี่ยนรูปนั้น "เร็วกว่า" มากกว่าวัตถุที่เปลี่ยนแปลงไม่ได้เนื่องจากอนุญาตให้มีการเพิ่มประสิทธิภาพได้มาก วัตถุไม่เปลี่ยนรูปหมายความว่าเราสามารถจัดสรรพื้นที่ให้กับมันได้ในเวลาสร้างและความต้องการพื้นที่จะไม่เปลี่ยนแปลง นอกจากนี้ยังมีสิ่งต่างๆเช่นประสิทธิภาพในการคัดลอกและประสิทธิภาพการเปรียบเทียบเนื่องจากมัน แก้ไข : นี่ไม่ใช่กรณีQueryDictอย่างที่ Gareth Rees ชี้ให้เห็น
  2. ในกรณีrequest.POSTนี้ดูเหมือนว่าไม่มีกิจกรรมใดในฝั่งเซิร์ฟเวอร์ที่จำเป็นต้องแก้ไขข้อมูลของคำขอ และด้วยเหตุนี้วัตถุที่ไม่เปลี่ยนรูปจึงมีความเหมาะสมมากกว่าไม่ต้องพูดถึงพวกเขามีข้อได้เปรียบในการแสดง
  3. วัตถุที่ไม่เปลี่ยนรูปสามารถใช้เป็นdictปุ่มซึ่งผมคิดว่าอาจจะเป็นที่ใดที่หนึ่งที่มีประโยชน์มากใน Django .. แก้ไข : ความผิดพลาดของฉันไม่เปลี่ยนรูปไม่ได้โดยตรงบ่งบอกhashable ; อย่างไรก็ตามวัตถุที่ล้างทำความสะอาดได้มักจะไม่เปลี่ยนรูปเช่นกัน
  4. เมื่อคุณผ่านไปมาrequest.POST(โดยเฉพาะอย่างยิ่งกับปลั๊กอินของบุคคลที่สามและออก) คุณสามารถคาดหวังได้ว่าวัตถุคำขอนี้จากผู้ใช้จะยังคงไม่เปลี่ยนแปลง

ในทางใดทางหนึ่งเหตุผลเหล่านี้ยังเป็นคำตอบทั่วไปสำหรับ "ไม่เปลี่ยนรูปหรือเปลี่ยนแปลงไม่ได้?" คำถาม. ฉันมั่นใจว่ามีข้อควรพิจารณาในการออกแบบมากกว่าข้างบนในเคส Django


1
กรณีสุดท้ายสำคัญจริงๆ มันเกี่ยวกับความปลอดภัยจริงๆ นี่คือเหตุผลที่ Django จัดเตรียมsessionsวิธีการรับและแก้ไขข้อมูลระหว่างรัฐในระยะสั้น
CppLearner

2
ประเด็นของคุณ (1) ไม่สามารถเป็นคำตอบในกรณีนี้ได้เนื่องจากPOSTเป็นQueryDictวัตถุและวัตถุเหล่านี้ไม่ได้รับประโยชน์จากการไม่เปลี่ยนรูป และประเด็นของคุณ (3) ไม่สามารถเป็นคำตอบได้เนื่องจากQueryDictอ็อบเจ็กต์ไม่สามารถแฮชได้จึงใช้เป็นคีย์พจนานุกรมไม่ได้
Gareth Rees

@GarethRees ขอบคุณที่ชี้ให้เห็นสิ่งเหล่านี้ แท้จริงฉันคิดผิด ฉันอัปเดตคำตอบเพื่อแก้ไขสิ่งเหล่านี้ ฉันควรให้ความสนใจมากกว่านี้QueryDictก่อนที่จะตอบกลับ
KZ

7
@CppLearner จุดรักษาความปลอดภัยดูเหมือนจะสงสัยเช่นrequests.POST._mutable = True; requests.POST['foo'] = 'bar'; request.POST._mutable = False
Dan Passaro

4

ฉันชอบที่มันไม่เปลี่ยนรูปไปโดยปริยาย ตามที่ระบุไว้คุณสามารถทำให้มันเปลี่ยนแปลงได้หากคุณต้องการ แต่คุณต้องชัดเจนเกี่ยวกับเรื่องนี้ มันเหมือนกับ 'ฉันรู้ว่าฉันสามารถทำให้ฟอร์มของฉันดีบั๊กกลายเป็นฝันร้ายได้ แต่ฉันรู้ว่าตอนนี้ฉันกำลังทำอะไรอยู่'


2

ฉันพบสิ่งนี้ในความคิดเห็นบน Stack Answer https://stackoverflow.com/a/2339963

และจะต้องไม่เปลี่ยนรูปจึงจะสร้างได้อย่างเฉื่อยชา การคัดลอกบังคับให้รับข้อมูล POST ทั้งหมด อาจไม่สามารถดึงข้อมูลทั้งหมดได้จนกว่าจะคัดลอก นอกจากนี้เพื่อให้เซิร์ฟเวอร์ WSGI แบบมัลติเธรดทำงานได้ดีพอสมควรจะมีประโยชน์หากไม่เปลี่ยนรูป


1

โปรดทราบ: multipartคำขอไม่เปลี่ยนรูปเนื่องจาก Django 1.11 https://github.com/django/django/blob/stable/1.11.x/django/http/multipartparser.py#L292

พวกเขาไม่แน่นอนในเวอร์ชันก่อนหน้า


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