web-dev-qa-db-fra.com

django - Pourquoi l'objet request.POST est-il immuable?

Comme le titre le demande, pourquoi les Django gars ont-ils décidé d'implémenter l'objet request.POST avec un querydict (ce qui, bien sûr, rend le tout immuable?)

Je sais que vous pouvez le mutifier en faisant une copie des données du post

post = request.POST.copy()

mais pourquoi faire ça? Ce serait sûrement plus simple de laisser la chose mutable de toute façon? Ou est-il utilisé pour une autre raison qui pourrait également poser problème?

106
bharal

C'est un peu un mystère, n'est-ce pas? Plusieurs théories superficiellement plausibles s’avèrent fausses lors d’une enquête:

  1. Alors que l'objet POST ne doit pas implémenter de méthodes de mutation? Non: l'objet POST appartient au Django.http.QueryDict class , qui implémente un ensemble complet de méthodes de mutation incluant __setitem__, __delitem__, pop et clear. Il implémente l'immuabilité en cochant un indicateur lorsque vous appelez l'une des méthodes de mutation. Et lorsque vous appelez la méthode copy, vous obtenez une autre instance de QueryDict avec l'indicateur mutable activé.

  2. Pour l'amélioration de la performance? Non: la classe QueryDict n'apporte aucun avantage en termes de performances lorsque le drapeau mutable est désactivé.

  3. Pour que l’objet POST puisse être utilisé comme clé de dictionnaire? Non: QueryDict les objets ne sont pas hashable.

  4. Pour que les données POST puissent être construites paresseusement (sans s’engager à lire toute la réponse), comme indiqué ici ? Je ne vois aucune preuve de cela dans le code: pour autant que je sache, toute la réponse est toujours lue, soit directement , ou via MultiPartParser = pour multipart réponses.

  5. Pour vous protéger contre les erreurs de programmation? J'ai vu cette affirmation, mais je n'ai jamais vu une bonne explication de ce que sont ces erreurs et de la façon dont l'immutabilité vous protège contre elles.

Dans tous les cas, POST est pas toujours immuable: lorsque la réponse est multipart, alors POST est mutable. Cela semble mettre le kibosh sur la plupart des théories auxquelles vous pourriez penser. (Sauf si ce comportement est un oubli.)

En résumé, je ne vois aucune justification claire dans Django pour que l'objet POST soit immuable pour les demandes non -multipart.

128
Gareth Rees

Si la demande était le résultat d'une soumission Django form, elle est alors raisonnable pour POST étant immutable pour assurer l'intégrité des données entre le formulaire soumission et le formulaire validation. Cependant, si la demande était pas envoyée via un Django form soumission, alors POST est mutable car il n'y a pas de validation de formulaire.

Vous pouvez toujours faire quelque chose comme ceci: (selon commentaire de @ leo-the-manic )

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

Mise à jour:

Gareth Rees avait raison de dire que les points 1 et 3 n'étaient pas valables dans ce cas. Bien que je pense que les points 2 et 4 sont toujours valables, je vais donc laisser les thèses ici.

(J'ai remarqué que le request.POST objet de Pyramid (Pylon) et Django est une forme de MultiDict. C'est donc une pratique plus courante que de faire request.POST immuable.)


Je ne peux pas parler pour les Django gars, bien qu'il me semble que cela pourrait arriver à cause de certaines de ces raisons:

  1. Performence. les objets immuables sont "plus rapides" que les objets mutables en ce qu'ils permettent des optimisations substantielles. Un objet est immuable signifie que nous pouvons lui allouer de l'espace au moment de la création et que l'espace requis ne change pas. Il a également des choses comme l'efficacité de la copie et l'efficacité de la comparaison à cause de cela. Edit: ce n'est pas le cas pour QueryDict comme l'a souligné Gareth Rees.
  2. Dans le cas de request.POST, il semble qu'aucune activité côté serveur ne doive avoir besoin de modifier les données de la demande. Et par conséquent, les objets immuables conviennent mieux, sans parler de leur avantage substantiel en termes de performances.
  3. Les objets immuables peuvent être utilisés en tant que clés dict que je suppose peut-être très utiles quelque part dans Django. Edit: mon erreur, immuable n'implique pas directement hashable ; Les objets hachurables sont cependant immuables .
  4. Quand vous passez autour de request.POST (en particulier pour les plug-ins tiers et les sorties), vous pouvez vous attendre à ce que cet objet de demande de l'utilisateur reste inchangé.

D'une certaine manière, ces raisons sont aussi des réponses génériques à "immuable vs mutable?" question. Je suis certain qu’il ya beaucoup plus de considérations de conception que ci-dessus dans le cas Django.

5
K Z

J'aime que ce soit immuable par défaut. Comme indiqué, vous pouvez le rendre mutable si vous en avez besoin, mais vous devez être explicite à ce sujet. C'est comme: "Je sais que je peux faire de ma fiche le débogage d'un cauchemar, mais je sais ce que je fais maintenant."

4
pawelmech

J'ai trouvé cela dans un commentaire sur Stack Answer https://stackoverflow.com/a/233996

Et il doit être immuable pour pouvoir être construit paresseusement. La copie oblige à obtenir toutes les données POST. Jusqu'à la copie, toutes les données ne peuvent pas être récupérées. De plus, pour qu'un serveur WSGI à plusieurs threads fonctionne raisonnablement, il est utile si ce paramètre est immuable.

2
Seaux

Veuillez noter que: multipart les requêtes sont immuables depuis Django 1.11 https://github.com/Django/django/blob/stable/1.11.x/Django/ http/multipartparser.py # L292

Ils étaient mutables dans les versions précédentes.

0
Alex Paramonov