django - mengapa objek request.POST tidak bisa diubah?

109

Seperti yang ditanyakan judul, mengapa orang-orang Django memutuskan untuk mengimplementasikan objek request.POST dengan querydict (yang, tentu saja, pada gilirannya, membuat semuanya tidak dapat diubah?)

Saya tahu Anda dapat memutifikasinya dengan membuat salinan data posting

post = request.POST.copy()

tapi kenapa melakukan ini? Tentunya akan lebih mudah jika membiarkan hal itu berubah? Atau apakah itu digunakan untuk beberapa alasan lain juga yang mungkin menyebabkan masalah?

bharal
sumber
1
Mengapa Anda ingin itu bisa berubah? Anda dapat mengambil data darinya dan menggunakan / memodifikasinya dalam tampilan Anda. Dengan menambahkan data ke dalamnya, Anda dapat menciptakan tayangan yang request.POSTtelah dikirimkan dengan lebih banyak data daripada yang sebenarnya.
Simeon Visser
11
Bukannya saya ingin itu bisa berubah. Tidak lebih dari, katakanlah, saya ingin es krim menjadi dingin. Dalam kasus es krim, jika tidak dingin itu meleleh dan kemudian Anda dimarahi karena membuat kekacauan besar. Tetapi dengan objek request.POST ... Maksud saya, jika saya akan mengacaukan kode saya, saya akan mengacaukannya. Saya tidak menyadari ada endemik pengembang yang menambahkan data ke objek POST dan Menyebabkan Masalah, jadi sepertinya aneh menargetkan untuk "diperbaiki".
bharal
Pertanyaan bagus; tidak pernah benar-benar memikirkannya.
Burhan Khalid
1
Ini muncul secara sporadis untuk saya karena klien saya terkadang mengirimkan data JSON (bisa berubah) dan terkadang pesan URL Form Encoded (tidak bisa diubah).
owenfi
2
Untuk penutur non-Inggris, "mutify" bukanlah sebuah kata - frase yang benar adalah "Anda dapat memutasinya" atau "Anda dapat mengubahnya". Juga tidak perlu gender pengembang - Anda dapat menggunakan "tim Django" atau "pengembang inti" daripada "pria".
alexmuller

Jawaban:

131

Ini sedikit misteri, bukan? Beberapa teori yang dangkal masuk akal ternyata salah dalam penyelidikan:

  1. Sehingga POSTobjek tersebut tidak harus menerapkan metode mutasi? Tidak: POSTobjek milik django.http.QueryDictkelas , yang menerapkan set lengkap metode mutasi termasuk __setitem__, __delitem__, popdan clear. Ini mengimplementasikan kekekalan dengan memeriksa tanda ketika Anda memanggil salah satu metode mutasi. Dan saat Anda memanggil copymetode, Anda mendapatkan QueryDictinstance lain dengan flag yang bisa berubah diaktifkan.

  2. Untuk peningkatan kinerja? Tidak: QueryDictkelas tidak mendapatkan keuntungan kinerja saat tanda yang bisa berubah dimatikan.

  3. Sehingga POSTobjek tersebut dapat digunakan sebagai kunci kamus? Tidak: QueryDictobjek tidak dapat di-hash.

  4. Sehingga POSTdata dapat dibangun dengan malas (tanpa berkomitmen untuk membaca keseluruhan respon), seperti diklaim di sini ? Saya tidak melihat bukti ini dalam kode: sejauh yang saya tahu, seluruh respon selalu dibaca, baik secara langsung , atau melalui MultiPartParseruntuk multiparttanggapan.

  5. Untuk melindungi Anda dari kesalahan pemrograman? Saya telah melihat klaim ini, tetapi saya belum pernah melihat penjelasan yang baik tentang apa kesalahan ini, dan bagaimana kekekalan melindungi Anda dari kesalahan tersebut.

Dalam hal apapun, POSTini tidak selalu berubah : ketika respon multipart, maka POSTbisa berubah. Ini tampaknya menempatkan omong kosong pada sebagian besar teori yang mungkin Anda pikirkan. (Kecuali jika perilaku ini merupakan pengawasan.)

Singkatnya, saya tidak dapat melihat alasan yang jelas di Django untuk POSTobjek menjadi tidak berubah untuk non- multipartpermintaan.

Gareth Rees
sumber
Saya telah memperhatikan banyak tepi kasar seperti ini di Django. Pasti masuk akal bagi seseorang pada suatu saat.
Dan Passaro
2
Saya menemukan ini di jawaban Stack lain: "Dan itu harus tidak dapat diubah sehingga dapat dibangun dengan malas. Salinan memaksa mendapatkan semua data POST. Hingga salinannya, mungkin tidak semuanya diambil. Selanjutnya, untuk WSGI multi-utas server bekerja dengan cukup baik, akan sangat membantu jika ini tidak dapat diubah "
Seaux
12
@Seaux, Anda tidak boleh membaca jawaban SO dengan malas ketika Anda bermaksud untuk mengomentarinya. ;-)
Chris Wesseling
3
@ChrisWesseling Saya melihat apa yang Anda lakukan di sana
Seaux
2
Lebih baik lagi, querydict bisa berubah ketika saya mengirim permintaan untuk menuntut klien pengujian django.
pengguna1158559
82

Jika permintaan adalah hasil dari formpenyerahan Django , maka masuk akal bagi POST immutableuntuk memastikan integritas data antara penyerahan formulir dan validasi formulir . Bagaimanapun, jika permintaan tidak dikirim melalui formpenyerahan Django , maka POST adalah mutablekarena tidak ada validasi formulir.

Anda selalu dapat melakukan sesuatu seperti ini: (sesuai komentar @ leo-the-manic )

#  .....
mutable = request.POST._mutable
request.POST._mutable = True
request.POST['some_data'] = 'test data'
request.POST._mutable = mutable
# ......
un33k
sumber
3
@JoshK: Saya rasa pemberi komentar ingin membuat POST bisa berubah, dan potongan kode dalam jawaban ini membantu.
ShreevatsaR
Anda dapat menambahkan kunci baru, nilai tetapi Anda tidak dapat mengubah data yang ada.
Vamsidhar Muggulla
Bagus. Dan saya yakin siapa pun yang menggunakan kode ini tahu apa yang dia lakukan.
John Pang
@VamsidharMuggulla Baik menambah dan mengubah adalah mungkin. Bahkan menghapus diperbolehkan.
Antony Hatchkins
5

Pembaruan :

Gareth Rees benar bahwa poin 1 & 3 tidak valid dalam kasus ini. Meskipun menurut saya poin 2 dan 4 masih berlaku, oleh karena itu saya akan meninggalkan tesis di sini.

(Saya perhatikan bahwa request.POSTobjek Pyramid (Pylon) dan Django adalah beberapa bentuk MultiDict. Jadi mungkin ini adalah praktik yang lebih umum daripada membuat request.POSTkekal.)


Saya tidak dapat berbicara untuk orang-orang Django, meskipun bagi saya tampaknya bisa karena beberapa alasan berikut:

  1. Pertunjukan . objek yang tidak dapat diubah "lebih cepat" daripada objek yang bisa berubah karena memungkinkan pengoptimalan yang substansial. Sebuah objek tidak dapat diubah artinya kita dapat mengalokasikan ruang untuknya pada waktu pembuatan , dan persyaratan ruang tidak berubah. Ia juga memiliki hal-hal seperti efisiensi penggandaan dan efisiensi perbandingan karenanya. Sunting : ini tidak terjadiQueryDictseperti yang ditunjukkan Gareth Rees.
  2. Dalam kasus request.POST, tampaknya tidak ada aktivitas di sisi server yang perlu mengubah data permintaan . Dan karenanya, objek yang tidak dapat diubah lebih cocok, belum lagi mereka memiliki keunggulan performa yang substansial.
  3. Objek tak berubah bisa digunakan sebagai dictkunci, yang saya kira bisa sangat berguna di suatu tempat di Django .. Edit : kesalahan saya, tak bisa diubah tidak secara langsung menyiratkan hashable ; objek yang dapat di- hash , bagaimanapun, biasanya juga tidak dapat diubah .
  4. Saat Anda menyebarkan request.POST(terutama ke plugin pihak ketiga dan keluar), Anda dapat berharap bahwa objek permintaan dari pengguna ini tidak akan berubah.

Dalam beberapa hal, alasan ini juga merupakan jawaban umum untuk "tidak berubah vs bisa berubah?" pertanyaan. Saya yakin ada lebih banyak pertimbangan desain daripada di atas dalam kasus Django.

KZ
sumber
1
Kasus terakhir sangat penting. Ini benar-benar tentang keamanan. Inilah mengapa Django menyediakan sessionscara hidup singkat untuk mendapatkan dan memodifikasi data antar status.
CppLearner
2
Poin Anda (1) tidak bisa menjadi jawaban dalam kasus ini, karena POSTadalah sebuah QueryDictobjek , dan objek-objek ini tidak mendapatkan keuntungan performa karena tidak dapat diubah. Dan poin Anda (3) tidak bisa menjadi jawabannya, karena QueryDictobjek tidak dapat di-hash, sehingga tidak bisa digunakan sebagai kunci kamus.
Gareth Rees
@GarethRees Terima kasih telah menunjukkan hal ini. Memang saya salah. Saya memperbarui jawaban saya untuk memperbaikinya. Saya seharusnya lebih memperhatikan QueryDictsebelum saya menjawab.
KZ
7
@CppLearner Titik keamanan tampaknya diperdebatkan, misalnyarequests.POST._mutable = True; requests.POST['foo'] = 'bar'; request.POST._mutable = False
Dan Passaro
4

Saya suka itu tidak dapat diubah secara default. Seperti yang ditunjukkan, Anda dapat membuatnya berubah jika perlu, tetapi Anda harus menjelaskannya secara eksplisit. Ini seperti 'Saya tahu bahwa saya dapat membuat formulir saya men-debug mimpi buruk tetapi saya tahu apa yang saya lakukan sekarang.'

pawelmech.dll
sumber
2

Saya menemukan ini di komentar di Stack Answer https://stackoverflow.com/a/2339963

Dan itu harus tidak dapat diubah agar dapat dibangun dengan malas. Salinan memaksa mendapatkan semua data POST. Hingga salinannya, mungkin tidak semuanya diambil. Lebih lanjut, agar server WSGI multi-utas bekerja dengan cukup baik, akan membantu jika ini tidak dapat diubah

Seaux
sumber