django - чому об'єкт request.POST незмінний?


109

Як заголовок запитує, чому хлопці Django вирішили реалізувати об'єкт request.POST із запитом (що, звичайно, в свою чергу, робить все це непорушним?)

Я знаю, що ви можете пошкодити це, зробивши копію даних публікації

post = request.POST.copy()

але навіщо це робити? Звичайно, було б простіше просто дозволити річ змінити все одно? Або він використовується також з якоїсь іншої причини, яка може спричинити проблему?


1
Чому ви хочете, щоб він мінявся? Ви можете взяти дані з них і використовувати / змінювати їх у вашому представленні. Додаючи до них дані, ви могли б створити враження, що request.POSTбуло подано з більшою кількістю даних, ніж насправді.
Симеон Віссер

11
Це не те, що я хочу, щоб це було змінним. Не більше ніж, скажімо, я хотів би, щоб морозиво було холодним. Що стосується морозива, то, якщо не холодно, воно тане, і тоді вас лаять за те, що роблять велику безладу. Але з об’єктом request.POST ... Я маю на увазі, якщо я збираюся накрутити свій код, я збираюся його накрутити. Мені не було відомо, що ендемік розробників додає дані до POST-об’єктів і викликає проблеми, тому здається, що націлити їх на "виправлення" дивним чином.
бхарал

Приємне запитання; ніколи не думав про це насправді.
Бурхан Халід

1
Це з'явилося для мене спорадично, тому що мій клієнт іноді надсилав повідомлення JSON (мутаційні), а іноді і URL-форми кодованих (незмінних) повідомлень.
Owenfi

2
Для тих, хто не говорить англійською мовою, "вимкнути" не є словом - правильна фраза "ви можете вимкнути його" або "ви можете змінити". Також не потрібно гендерно розробляти розробників - ви можете скористатися командою "Django" або "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є змінною. Це, здається, ставить кібош на більшість теорій, про які ви можете подумати. (Якщо ця поведінка не є недоглядом.)

Підсумовуючи, я не бачу чіткого обгрунтування в Джанго, щоб POSTоб'єкт був непорушним для не multipartзапитів.


Я помітив тони таких шорстких країв у Джанго. Ви, мабуть, мали сенс комусь у якийсь момент.
Дан Пассаро

2
Я знайшов це в іншій відповіді стека: "І це повинно бути непорушним, щоб його можна було лінь вбудувати. Копія змушує отримувати всі дані POST. До копії вона може не отримати всі. Далі, для багатопотокової WSGI сервер працювати достатньо добре, корисно, якщо це непорушно "
Seaux

12
@Seaux, ти не повинен ліниво читати відповіді SO, коли ти маєш намір їх коментувати. ;-)
Кріс Вессілінг

3
@ChrisWesseling Я бачу, що ти там робив
Seaux

2
Ще краще, що запит є змінним, коли я надсилаю запит, подаючи позов на клієнта тесту django.
користувач1158559

82

Якщо запит був результатом formподання Django , тоді POST доцільно immutableзабезпечити цілісність даних між подачею форми та валідацією форми . Однак якщо запит не був надісланий через formподання Джанго , тоді 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

Ви можете додати новий ключ, значення, але не можете змінити існуючі дані.
Вамсідхар Маггулла

Приємно. І я впевнений, хто використовує цей код, знає, що він чи вона робить.
Джон Панг

@VamsidharMuggulla Можливе додавання та змінення. Дозволено навіть видалення.
Антоні Хеткінс

5

Оновлення :

Гарет Різ мав рацію, що пункти 1 та 3 в цьому випадку не дійсні. Хоча я вважаю, що пункти 2 і 4 все ще діють, тому я залишу тези тут.

(Я помітив, що request.POSTоб'єктом і Піраміди (Пілона), і Джанго є якась форма MultiDict. Тож, можливо, це є звичайнішою практикою, ніж робити request.POSTнепорушним.)


Я не можу говорити за хлопців Джанго, хоча мені здається, що це могло через деякі з цих причин:

  1. Виконання . незмінні об'єкти «швидші» над змінними, оскільки вони дозволяють істотно оптимізувати. Об'єкт незмінний означає, що ми можемо виділити для нього простір під час створення , а вимоги до простору не змінюються. У нього також є такі ефекти, як ефективність копіювання та ефективність порівняння. Правка : це не так,QueryDictяк вказував Гарет Різ.
  2. У випадку request.POST, схоже, жодна активність на стороні сервера не потребує зміни даних запиту . А отже, непорушні предмети більше підходять, не кажучи вже про те, що вони мають значну перевагу у виконанні.
  3. Незмінні об'єкти можуть використовуватися як dictключі, які, напевно, можуть бути дуже корисними десь у Django. Редагувати : моя помилка, незмінна безпосередньо не передбачає доступність ; однак об'єкти, що змішуються , як правило, також незмінні .
  4. Коли ви переходите навколо request.POST(особливо до сторонніх плагінів і вихід), ви можете очікувати, що цей запит від користувача залишиться незмінним.

У чомусь ці причини також є загальними відповідями на "непорушний проти змінного?" питання. Я впевнений, що у випадку Джанго є набагато більше міркувань щодо дизайну, ніж вище.


1
Остання справа справді важлива. Мова йде про безпеку. Саме тому Джанго надає sessionsкороткочасний спосіб отримання та зміни даних між державами.
CppLearner

2
Ваша точка (1) не може бути відповіддю в цьому випадку, оскільки POSTце QueryDictоб'єкт , і ці об’єкти не отримують користі від продуктивності від непорушності. І ваша думка (3) не може бути відповіддю, оскільки QueryDictоб’єкти не підлягають доступу, і тому їх не можна використовувати як словникові ключі.
Гарет Різ

@GarethRees Дякую, що вказали на це. Справді я помилявся. Я оновив свою відповідь, щоб виправити це. Я мав би приділити більше уваги, QueryDictперш ніж я відповів.
KZ

7
@CppLearner Пункт безпеки здається суперечливим, наприкладrequests.POST._mutable = True; requests.POST['foo'] = 'bar'; request.POST._mutable = False
Dan Passaro

4

Мені подобається, що вона за замовчуванням незмінна. Як зазначалося, ви можете зробити його зміненим, якщо вам потрібно, але ви повинні бути чітко про це. Це як "я знаю, що можу зробити свою форму налагодженням кошмаром, але я знаю, що зараз роблю".


2

Я знайшов це в коментарі до відповіді на стек https://stackoverflow.com/a/2339963

І він повинен бути незмінним, щоб його можна було ліниво збудувати. Копія змушує отримувати всі дані POST. До тих пір, поки копія може не отримати все. Крім того, щоб багатопотоковий сервер WSGI працював досить добре, корисно, якщо це непорушно


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.