django MultiValueDictKeyError, como faço para lidar com isso

174

Estou tentando salvar um objeto no meu banco de dados, mas está gerando um MultiValueDictKeyErrorerro.

Os problemas estão no formulário, o is_privateé representado por uma caixa de seleção. Se a caixa de seleção NÃO estiver selecionada, obviamente nada será passado. É aqui que o erro é descartado.

Como faço para lidar adequadamente com essa exceção e capturá-la?

A linha é

is_private = request.POST['is_private']
dotty
fonte
1
Uma boa idéia seria nos mostrar todo o erro e o rastreio. Também nos mostra mais essa parte do código em que o erro é gerado.
Rzetterberg 5/05
1
Alguém pode explicar por que esse erro ocorre? Eu vi esse erro quando eu uso Modelviewset diferente no resto do django .....
Amrit
1
significa simplesmente: a chave 'is_private' não existe!
precisa saber é

Respostas:

281

Use o getmétodo do MultiValueDict . Isso também está presente nos dictos padrão e é uma maneira de buscar um valor e fornecer um padrão se ele não existir.

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

Geralmente,

my_var = dict.get(<key>, <default>)
adamnfish
fonte
2
Isso me dá um valor None, mas estou enviando o valor no POST: /
Jesus Almaral - Hackaprende
É o comportamento correto. A caixa de seleção envia checkedquando está marcada, mas envia nullse não estiver marcada. Você pode verificar isso no painel "Rede" da ferramenta Chrome / Firefox DEV. É por isso que você define Falsecomo o valor padrão: se obtido null, faça-o false.
WesternGun 7/0318
78

Escolha o que é melhor para você:

1

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

Se a is_privatechave estiver presente em request.POST, a is_privatevariável será igual a ela, caso contrário, será igual a 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
Luz cinza
fonte
12
Realmente não posso recomendar número 3.
Joe
6
Parece apenas um abuso do sistema de exceções. As exceções devem ser para lidar com comportamentos excepcionais (ou seja, comportamentos que você sabe que podem acontecer e devem lidar com eles, mas que não espera no fluxo normal do programa). Nesse caso, a exceção será lançada e capturada em 50% dos fluxos possíveis do programa. Adicionado a isso é a desaceleração. Não sei os detalhes de como ele funciona no Python, mas eu imaginaria que um rastreamento de pilha caro estaria envolvido.
Joe
13
de django.utils.datastructures import MultiValueDictKeyError
Akseli Palén
8
@ Joe - Em Python, essa abordagem é bastante comum. Se você estiver capturando a exceção, ela não gerará automaticamente um rastreamento de pilha. docs.python.org/2/glossary.html#term-eafp
bjudson 22/09/13
9
Não há nada de errado com a etapa 3. Chamamos isso mais fácil de pedir perdão do que permissão (EAFP), e esse é um estilo de codificação altamente recomendado em Python. Muitas postagens no StackOverflow já discutiram isso.
Bobort 19/09/17
12

Você entende isso porque está tentando obter uma chave de um dicionário quando ele não está lá. Você precisa testar se está lá primeiro.

experimentar:

is_private = 'is_private' in request.POST

ou

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

dependendo dos valores que você está usando.

Joe
fonte
5

Por que você não tentou definir is_privateem seus modelos como default=False?

class Foo(models.Models):
    is_private = models.BooleanField(default=False)
Edson Dota
fonte
2
Isso não impediria o erro que ele está recebendo ao verificar manualmente o POST quanto ao valor.
Apollo Data
4

Outra coisa a lembrar é que request.POST['keyword']se refere ao elemento identificado pelo nameatributo html especificado keyword.

Portanto, se seu formulário for:

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

então, request.POST['keyword']e request.POST['results']conterá o valor dos elementos de entrada keyworde results, respectivamente.

Leo
fonte
1

Primeiro verifique se o objeto de solicitação possui o parâmetro-chave 'is_private'. Na maioria dos casos, esse MultiValueDictKeyError ocorreu por falta de chave no objeto de solicitação semelhante ao dicionário. Como o dicionário é uma chave não ordenada, o par de valores "memórias associativas" ou "matrizes associativas"

Em outra palavra. request.GET ou request.POST é um objeto semelhante ao dicionário que contém todos os parâmetros de solicitação. Isto é específico para o Django.

O método get () retorna um valor para a chave especificada se a chave estiver no dicionário. Se a chave não estiver disponível, retornará o valor padrão Nenhum.

Você pode lidar com esse erro colocando:

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

Para mim, esse erro ocorreu no meu projeto django devido ao seguinte:

  1. Inseri um novo hiperlink em meu home.html presente na pasta de modelos do meu projeto, como abaixo:

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

  2. No views.py, eu tinha as seguintes definições de count e 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. No urls.py, eu tinha os seguintes padrões de 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"),
    ]

Como pode ser visto no n. 3 acima, no último padrão de URL, eu estava chamando incorretamente o views.count, enquanto eu precisava chamá-lo. A fulltext = request.GET['fulltext']função line in count (que foi chamada erroneamente por causa da entrada incorreta nos padrões de URL) do views.py lançou a exceção multivaluedictkeyerror.

Então mudei o último padrão de URL em urls.py para o correto path('about/',views.about,name="about"), ou seja , e tudo funcionou bem.

Aparentemente, em geral, um programador iniciante no django pode cometer o erro que cometi ao chamar outra função de visualização para um URL, o que pode estar esperando um conjunto diferente de parâmetros ou passando um conjunto diferente de objetos em sua chamada de renderização, em vez do comportamento pretendido.

Espero que isso ajude algum programador iniciante no django.

TNT
fonte