django - почему объект request.POST неизменен?

110

Как видно из названия, почему ребята из Django решили реализовать объект request.POST с помощью querydict (что, конечно, в свою очередь, делает все это неизменным?)

Я знаю, что вы можете изменить это, сделав копию данных публикации

post = request.POST.copy()

но зачем это делать? Конечно, было бы проще просто разрешить этому объекту быть изменяемым? Или он используется по какой-то другой причине, которая может вызвать проблемы?

бхарал
источник
1
Почему вы хотите, чтобы он был изменяемым? Вы можете взять из него данные и использовать / изменить их в своем представлении. Добавляя в него данные, вы можете создать впечатление, что request.POSTбыло отправлено больше данных, чем было на самом деле.
Симеон Виссер
11
Не то чтобы я хотел, чтобы он был изменчивым. Не больше, чем, скажем, я хочу, чтобы мороженое было холодным. Однако в случае с мороженым, если оно не холодное, оно тает, и вас ругают за то, что вы устроили большой беспорядок. Но с объектом request.POST ... То есть, если я собираюсь испортить свой код, я собираюсь испортить его. Я не знал, что существует множество разработчиков, добавляющих данные к объектам POST и вызывающих проблемы, так что это кажется странным, чтобы «исправить».
bharal
Хороший вопрос; никогда не думал об этом на самом деле.
Бурхан Халид
1
Это возникало у меня время от времени, потому что мой клиент иногда отправлял данные JSON (изменяемые), а иногда и сообщения с кодировкой URL-формы (неизменяемые).
owenfi
2
Для людей, не говорящих по-английски, «mutify» не является словом - правильная фраза - «вы можете изменить это» или «вы можете изменить это». Также нет необходимости гендерно разделять разработчиков - вы можете использовать «команду Django» или «основные разработчики», а не «ребята».
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изменчиво. Похоже, это ставит под сомнение большинство теорий, которые вы можете придумать. (Если это поведение не является недосмотром.)

Таким образом, я не вижу в Django четкого обоснованияPOST неизменности объекта для не- multipartзапросов.

Гарет Рис
источник
Я заметил множество неровностей в Django. Хотя, должно быть, в какой-то момент это имело смысл для кого-то.
Дэн Пассаро
2
Я нашел это в другом ответе стека: «И он должен быть неизменяемым, чтобы его можно было строить лениво. Копия заставляет получать все данные POST. До копирования они могут быть извлечены не все. Кроме того, для многопоточного WSGI сервер должен работать достаточно хорошо, будет полезно, если он будет неизменным »
Seaux
12
@Seaux, вы не должны лениво читать SO-ответы, когда собираетесь их комментировать. ;-)
Крис Весселинг
3
@ChrisWesseling, я вижу, что вы там делали
Seaux
2
Более того, querydict может изменяться, когда я отправляю запрос в суд с тестовым клиентом django.
user1158559
82

Если запрос был результатом Джанго formпредставления, то разумно для POST быть immutableдля обеспечения целостности данных между формой представлением и формой проверкой . Однако, если запрос не был отправлен через отправку Django form, то POST - mutableэто отсутствие проверки формы.

Вы всегда можете сделать что-то вроде этого: (согласно комментарию @ leo-the-manic )

#  .....
mutable = request.POST._mutable
request.POST._mutable = True
request.POST['some_data'] = 'test data'
request.POST._mutable = mutable
# ......
un33k
источник
3
@JoshK: Думаю, комментатор хотел сделать POST изменяемым, и фрагмент кода в этом ответе помог.
ShreevatsaR
Вы можете добавить новый ключ, значение, но не можете изменить существующие данные.
Vamsidhar Muggulla
Ницца. И я уверен, что тот, кто использует этот код, знает, что делает.
Джон Панг
@VamsidharMuggulla Возможно как добавление, так и изменение. Допускается даже удаление.
Энтони Хэтчкинс,
5

Обновление :

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

(Я заметил, что request.POSTобъект как Pyramid (Pylon), так и Django является некоторой формой MultiDict. Так что, возможно, это более распространенная практика, чем создание request.POSTнеизменяемого.)


Я не могу говорить за ребят из Django, хотя мне кажется, что это могло произойти по некоторым из следующих причин:

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

В каком-то смысле эти причины также являются общими ответами на вопрос «неизменный vs изменчивый?» вопрос. Я уверен, что в случае с Django существует гораздо больше соображений по поводу дизайна, чем указано выше.

KZ
источник
1
Последний случай действительно важен. Это действительно о безопасности. Вот почему Django предоставляет 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 работал достаточно хорошо, полезно, если он является неизменным.

Seaux
источник