Erreur django MultiValueDictKeyError, comment y faire face

174

J'essaie d'enregistrer un objet dans ma base de données, mais cela génère une MultiValueDictKeyErrorerreur.

Le problème réside dans le formulaire, le is_privateest représenté par une case à cocher. Si la case à cocher n'est PAS cochée, évidemment rien n'est passé. C'est là que l'erreur est jetée.

Comment gérer correctement cette exception et l'attraper?

La ligne est

is_private = request.POST['is_private']
dingue
la source
1
Une bonne idée serait de nous montrer toute l'erreur et la trace. Montrez-nous également plus de cette partie du code où l'erreur est générée.
rzetterberg
1
Quelqu'un peut-il expliquer pourquoi cette erreur se produit? J'ai vu cette erreur lorsque j'utilise différents Modelviewset dans django rest .....
Amrit
1
cela signifie simplement: la clé 'is_private' n'existe pas!
ThePhi

Réponses:

282

Utilisez la getméthode de MultiValueDict . Ceci est également présent sur les dictionnaires standard et est un moyen de récupérer une valeur tout en fournissant une valeur par défaut si elle n'existe pas.

is_private = request.POST.get('is_private', False)

Généralement,

my_var = dict.get(<key>, <default>)
adamnfish
la source
2
Cela me donne une valeur None mais
j'envoie
C'est le comportement correct .. case à cocher envoyer checkedquand est cochée mais enverra nullsi elle n'est pas cochée. Vous pouvez le vérifier dans le panneau "Réseau" de l'outil Chrome / Firefox DEV. C'est pourquoi vous définissez Falsecomme valeur par défaut: si obtenu null, créez-le false.
WesternGun
78

Choisissez ce qui vous convient le mieux:

1

is_private = request.POST.get('is_private', False);

Si la is_privateclé est présente dans request.POST, la is_privatevariable lui sera égale, sinon, alors elle sera égale à False.

2

if 'is_private' in request.POST:
    is_private = request.POST['is_private']
else:
    is_private = False

3

from django.utils.datastructures import MultiValueDictKeyError
try:
    is_private = request.POST['is_private']
except MultiValueDictKeyError:
    is_private = False
Lumière argentée
la source
12
Je ne peux vraiment pas recommander le numéro 3.
Joe
6
Cela semble être un abus du système d'exception. Les exceptions doivent concerner la gestion des comportements exceptionnels (c'est-à-dire des comportements que vous savez que cela peut se produire et que vous devez gérer, mais auxquels vous ne vous attendez pas dans le déroulement normal du programme). Dans ce cas, l'exception sera lancée et interceptée dans 50% des flux de programme possibles. À cela s'ajoute le ralentissement. Je ne connais pas les détails de son fonctionnement en Python, mais j'imagine qu'un stack-trace coûteux serait impliqué.
Joe
13
de django.utils.datastructures import MultiValueDictKeyError
Akseli Palén
8
@Joe - En Python, cette approche est assez courante. Si vous interceptez l'exception, il ne générera pas automatiquement de trace de pile. docs.python.org/2/glossary.html#term-eafp
bjudson
9
Il n'y a rien de mal à l'étape 3. Nous appelons cela plus facile de demander pardon que la permission (EAFP), et c'est un style de codage fortement recommandé en Python. De nombreux articles sur StackOverflow en ont même discuté.
Bobort
12

Vous obtenez cela parce que vous essayez d'obtenir une clé d'un dictionnaire alors qu'elle n'est pas là. Vous devez d'abord tester s'il y est.

essayer:

is_private = 'is_private' in request.POST

ou

is_private = 'is_private' in request.POST and request.POST['is_private']

selon les valeurs que vous utilisez.

Joe
la source
5

Pourquoi n'avez-vous pas essayé de définir is_privatedans vos modèles comme default=False?

class Foo(models.Models):
    is_private = models.BooleanField(default=False)
Edson Dota
la source
2
Cela n'empêcherait pas l'erreur qu'il obtient en vérifiant manuellement la valeur du POST.
Apollo Data
4

Une autre chose à retenir est que request.POST['keyword']fait référence à l'élément identifié par l' nameattribut html spécifié keyword.

Donc, si votre formulaire est:

<form action="/login/" method="POST">
  <input type="text" name="keyword" placeholder="Search query">
  <input type="number" name="results" placeholder="Number of results">
</form>

puis, request.POST['keyword']et request.POST['results']contiendra la valeur des éléments d'entrée keywordet results, respectivement.

Leo
la source
1

Vérifiez d'abord si l'objet de requête a le paramètre clé 'is_private'. Dans la plupart des cas, cette MultiValueDictKeyError s'est produite pour une clé manquante dans l'objet de requête de type dictionnaire. Étant donné que le dictionnaire est une clé non ordonnée, une paire de valeurs "mémoires associatives" ou "tableaux associatifs"

Dans un autre mot. request.GET ou request.POST est un objet de type dictionnaire contenant tous les paramètres de requête. Ceci est spécifique à Django.

La méthode get () renvoie une valeur pour la clé donnée si la clé est dans le dictionnaire. Si la clé n'est pas disponible, renvoie la valeur par défaut None.

Vous pouvez gérer cette erreur en mettant:

is_private = request.POST.get('is_private', False);
Projesh Bhoumik
la source
1

Pour moi, cette erreur s'est produite dans mon projet django pour les raisons suivantes:

  1. J'ai inséré un nouveau lien hypertexte dans mon home.html présent dans le dossier templates de mon projet comme ci-dessous:

    <input type="button" value="About" onclick="location.href='{% url 'about' %}'">

  2. Dans views.py, j'avais les définitions suivantes de count et about:

   def count(request):
           fulltext = request.GET['fulltext']
           wordlist = fulltext.split()
           worddict = {}
           for word in wordlist:
               if word in worddict:
                   worddict[word] += 1
               else:
                   worddict[word] = 1
                   worddict = sorted(worddict.items(), key = operator.itemgetter(1),reverse=True)
           return render(request,'count.html', 'fulltext':fulltext,'count':len(wordlist),'worddict'::worddict})

   def about(request): 
       return render(request,"about.html")
  1. Dans urls.py, j'avais les modèles d'URL suivants:
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('',views.homepage,name="home"),
        path('eggs',views.eggs),
        path('count/',views.count,name="count"),
        path('about/',views.count,name="about"),
    ]

Comme on peut le voir dans le no. 3 ci-dessus, dans le dernier modèle d'URL, j'appelais incorrectement views.count alors que j'avais besoin d'appeler views.about. Cette ligne fulltext = request.GET['fulltext']dans la fonction count (qui a été appelée par erreur en raison d'une entrée incorrecte dans les modèles d'url) de views.py a levé l'exception multivaluedictkeyerror.

Ensuite, j'ai changé le dernier modèle d'URL dans urls.py par le bon path('about/',views.about,name="about"), et tout a bien fonctionné.

Apparemment, en général, un programmeur débutant dans django peut faire l'erreur que j'ai faite d'appeler à tort une autre fonction de vue pour une URL, qui pourrait s'attendre à un ensemble de paramètres différent ou à transmettre un ensemble d'objets différents dans son appel de rendu, plutôt que le comportement prévu.

J'espère que cela aidera certains programmeurs débutants à django.

TNT
la source