django Błąd MultiValueDictKeyError, jak sobie z nim radzić

174

Próbuję zapisać obiekt w mojej bazie danych, ale generuje MultiValueDictKeyErrorbłąd.

Problemy znajdują się w formularzu, is_privateoznaczono je polem wyboru. Jeśli pole wyboru NIE jest zaznaczone, oczywiście nic nie jest przekazywane. W tym miejscu błąd zostaje wyrzucony.

Jak prawidłowo poradzić sobie z tym wyjątkiem i go złapać?

Linia jest

is_private = request.POST['is_private']
rozsiany
źródło
1
Dobrym pomysłem byłoby pokazanie nam całego błędu i śladu. Pokaż nam również więcej części kodu, w których wystąpił błąd.
rzetterberg
1
Czy ktoś może wyjaśnić, dlaczego występuje ten błąd? Widziałem ten błąd, gdy używam innego Modelviewset w reszcie django .....
Amrit
1
oznacza to po prostu: klucz „is_private” nie istnieje!
ThePhi

Odpowiedzi:

281

Użyj metody MultiValueDict get. Jest to również obecne w standardowych dyktach i jest sposobem na pobranie wartości przy jednoczesnym zapewnieniu wartości domyślnej, jeśli nie istnieje.

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

Ogólnie,

my_var = dict.get(<key>, <default>)
adamnfish
źródło
2
Daje mi to wartość None, ale wysyłam wartość w POST: /
Jesus Almaral - Hackaprende
Jest to poprawne zachowanie .. pole wyboru wyślij, checkedgdy jest zaznaczone, ale wyśle, nulljeśli nie jest zaznaczone. Możesz to sprawdzić w panelu „Sieć” narzędzia Chrome / Firefox DEV. Dlatego ustawiasz Falsejako wartość domyślną: jeśli masz null, zrób to false.
WesternGun
78

Wybierz to, co jest dla Ciebie najlepsze:

1

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

Jeśli is_privateklucz występuje w request.POST, is_privatezmienna będzie mu równa, jeśli nie, to będzie równa 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
Srebrne światło
źródło
12
Naprawdę nie mogę polecić numeru 3.
Joe
6
To po prostu wygląda na nadużycie systemu wyjątków. Wyjątki powinny dotyczyć obsługi wyjątkowego zachowania (tj. Zachowania, o którym wiesz, że może się zdarzyć iz którym musisz sobie poradzić, ale którego nie oczekujesz w normalnym przebiegu programu). W takim przypadku wyjątek zostanie zgłoszony i przechwycony w 50% możliwych przepływów programu. Do tego dochodzi spowolnienie. Nie znam szczegółów, jak to działa w Pythonie, ale wyobrażam sobie, że wymagałoby to kosztownego śledzenia stosu.
Joe
13
from django.utils.datastructures import MultiValueDictKeyError
Akseli Palén
8
@Joe - W Pythonie takie podejście jest dość powszechne. Jeśli przechwytujesz wyjątek, nie generuje on automatycznie śladu stosu. docs.python.org/2/glossary.html#term-eafp
bjudson
9
Nie ma nic złego w kroku 3. Nazywamy to łatwiejszym prosić o przebaczenie niż pozwolenie (EAFP) i jest to wysoce zalecany styl kodowania w Pythonie. Wiele postów na StackOverflow nawet o tym dyskutowało.
Bobort
12

Otrzymujesz to, ponieważ próbujesz uzyskać klucz ze słownika, gdy go tam nie ma. Musisz najpierw sprawdzić, czy jest tam.

próbować:

is_private = 'is_private' in request.POST

lub

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

w zależności od używanych wartości.

Joe
źródło
5

Dlaczego nie próbowałeś zdefiniować is_privatew swoich modelach jako default=False?

class Foo(models.Models):
    is_private = models.BooleanField(default=False)
Edson Dota
źródło
2
To nie zapobiegłoby błędowi, który otrzymuje podczas ręcznego sprawdzania wartości POST.
Apollo Data
4

Inną rzeczą do zapamiętania jest to, że request.POST['keyword']odnosi się do elementu identyfikowanego przez określony nameatrybut HTML keyword.

Jeśli więc Twój formularz to:

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

następnie, request.POST['keyword']i request.POST['results']będzie zawierać odpowiednio wartość elementów wejściowych keywordi results.

Lew
źródło
1

Najpierw sprawdź, czy obiekt żądania ma parametr klucza „is_private”. W większości przypadków ten MultiValueDictKeyError wystąpił z powodu brakującego klucza w obiekcie żądania podobnym do słownika. Ponieważ słownik jest kluczem nieuporządkowanym, para wartości „pamięci asocjacyjne” lub „tablice asocjacyjne”

Innymi słowy. request.GET lub request.POST to obiekt podobny do słownika, zawierający wszystkie parametry żądania. Jest to specyficzne dla Django.

Metoda get () zwraca wartość dla podanego klucza, jeśli klucz znajduje się w słowniku. Jeśli klucz nie jest dostępny, zwraca wartość domyślną Brak.

Możesz obsłużyć ten błąd, umieszczając:

is_private = request.POST.get('is_private', False);
Projesh Bhoumik
źródło
1

U mnie ten błąd wystąpił w moim projekcie django z następujących powodów:

  1. Wstawiłem nowe hiperłącze do mojego home.html obecnego w folderze szablonów mojego projektu, jak poniżej:

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

  2. W views.py miałem następujące definicje count i 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. W urls.py miałem następujące wzorce adresów URL:
    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"),
    ]

Jak widać w nr. 3 powyżej, w ostatnim wzorcu adresu URL błędnie wywoływałem views.count, podczas gdy musiałem wywoływać views.about. Ta linia fulltext = request.GET['fulltext']funkcji count (która została błędnie wywołana z powodu błędnego wpisu w urlpatterns) views.py spowodowała wyjątek multivaluedictkeyerror.

Następnie zmieniłem ostatni wzorzec adresu URL w urls.py na prawidłowy, tj. path('about/',views.about,name="about")I wszystko działało dobrze.

Najwyraźniej początkujący programista w django może popełnić błąd, który popełniłem, błędnie wywołując inną funkcję widoku dla adresu URL, która może oczekiwać innego zestawu parametrów lub przekazywania innego zestawu obiektów w wywołaniu renderowania, zamiast zamierzonego zachowania.

Mam nadzieję, że pomoże to nowicjuszowi w django.

TNT
źródło