2010-08-20 13 views
13

Recibo un KeyError para 'contraseña' cuando intento enviar mi formulario.Método Django clean arrojando KeyError en POST

traza:

Request Method: POST 
Request URL: http://localhost:8000/register/ 
Django Version: 1.2.1 
Python Version: 2.7.0 
Installed Applications: 
['django.contrib.auth', 
'django.contrib.contenttypes', 
'django.contrib.sessions', 
'djangoproject1.authentication'] 
Installed Middleware: 
('django.middleware.common.CommonMiddleware', 
'django.contrib.sessions.middleware.SessionMiddleware', 
'django.contrib.auth.middleware.AuthenticationMiddleware') 


Traceback: 
File "C:\Python27\lib\site-packages\django\core\handlers\base.py" in get_response 
    100.      response = callback(request, *callback_args, **callback_kwargs) 
File "C:\Users\jec23\My Java Projects\djangoproject1\src\djangoproject1\authentication\views.py" in register 
    20.   if rf.is_valid() and pf.is_valid(): 
File "C:\Python27\lib\site-packages\django\forms\forms.py" in is_valid 
    121.   return self.is_bound and not bool(self.errors) 
File "C:\Python27\lib\site-packages\django\forms\forms.py" in _get_errors 
    112.    self.full_clean() 
File "C:\Python27\lib\site-packages\django\forms\forms.py" in full_clean 
    268.   self._clean_form() 
File "C:\Python27\lib\site-packages\django\forms\forms.py" in _clean_form 
    296.    self.cleaned_data = self.clean() 
File "C:\Users\jec23\My Java Projects\djangoproject1\src\djangoproject1\authentication\forms.py" in clean 
    16.   if self.cleaned_data['cpassword']!=self.cleaned_data['password']: 

Exception Type: KeyError at /register/ 
Exception Value: 'password' 

vistas:

def register(request): 
    if request.method == 'POST': 
     rf = forms.RegisterForm(request.POST) 
     pf = forms.ProfileForm(request.POST) 
     if rf.is_valid() and pf.is_valid(): 
      newuser = User(username=rf.cleaned_data['username'],email=rf.cleaned_data['email']) 
      newuser.set_password(rf.cleaned_data['password']) 
      newuser.save() 
      profile = pf.save(commit=False) 
      profile.user = newuser 
      profile.save() 
      return HttpResponseRedirect("/register-success/") 
     else: 
      return render_to_response("authentication/index.html", {'form1': rf, 'form2':pf}) 
    else: 
     return main(request) 

formas:

class RegisterForm(forms.Form): 
    username = forms.CharField(min_length=6,max_length=15) 
    password = forms.CharField(min_length=6,max_length=15,widget = forms.PasswordInput()) 
    cpassword = forms.CharField(label='Confirm Password',widget = forms.PasswordInput()) 
    email = forms.EmailField(label='E-mail Address') 

    def clean(self): 
     if self.cleaned_data['cpassword']!=self.cleaned_data['password']: 
      raise forms.ValidationError("Passwords don't match") 
     return self.cleaned_data 

class ProfileForm(forms.ModelForm): 
    phonenumber = forms.CharField(label='Phone Number') 

    class Meta: 
     model = UserProfile 
     exclude = ('user') 
+0

¿Puedes publicar el código que está utilizando este formulario? –

+0

incluido ver código – JPC

+0

¿Se puede publicar también el código de la plantilla? –

Respuesta

10

Aha! El mensaje de error de validación que está viendo no es en realidad un mensaje de error de validación. Dejame explicar. Al representar la instancia modelo de formulario utilizando as_p, que hace que cada campo de la siguiente manera:

<p><label ...>fieldname</label> <input ... name="fieldname" /> HELP TEXT IF ANY</p> 

La cadena Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters que está viendo a la derecha del campo no es más que el texto de ayuda. Este texto de ayuda se toma de la definición del modelo; puede verificarlo visitando django/contrib/auth/models.py e inspeccionando la definición de la clase User.

Al anular el campo username, se omite el texto de ayuda. Naturalmente, el "error" desaparece.

Para verificar esta teoría, haga lo siguiente en su método main.

def main(request): 
    uf = forms.UserForm() 
    upf = forms.UserProfileForm() 
    print "User form is bound:%s errors:%s" % (uf.is_bound, uf.errors) 
    return render_to_response("authentication/index.html", {'form1': uf, 'form2':upf}) 

actualización

if self.cleaned_data['cpassword']!=self.cleaned_data['password']: 

Esta línea puede causar problemas cuando el usuario no proporciona uno o ambos de password y cpassword. Por ejemplo, trate desde el shell de Django:

>>> data = dict(username = 'admin', cpassword = 'foo', email='[email protected]') 
>>> f = RegisterForm(data) 
>>> f.is_bound 
True 
>>> f.is_valid() 

Traceback (most recent call last): 
    ... 
    File "<pyshell#2>", line 8, in clean 
    if self.cleaned_data['cpassword']!=self.cleaned_data['password']: 
KeyError: 'password' 

cambiar el método de su forma clean para asegurarse de que ambos valores están presentes antes de comparar. Algo como esto:

def clean(self): 
    password = self.cleaned_data.get('password', None) 
    cpassword = self.cleaned_data.get('cpassword', None) 
    if password and cpassword and (password == cpassword): 
     return self.cleaned_data 
    else: 
     raise forms.ValidationError("Passwords don't match") 
+0

¡Ah!Eso tiene mucho sentido. Nunca me hubiera dado cuenta de eso. Me molestó un poco con ModelForm para el usuario porque tenía que redefinir los campos y todavía estaba obteniendo ese KeyError por algún motivo. Terminé usando un formulario regular y simplemente creando el usuario. – JPC

+0

¿Es posible hacer que el texto de ayuda desaparezca sin anular? – JPC

+0

@JPC: puede anular el método '__init__' del formulario y establecer' self.fields ['username']. Help_text = None'. Un poco difícil en mi humilde opinión. Alternativamente, puede usar otro método para mostrar el formulario donde ignora el texto de ayuda. –

11

Desde mi propia experiencia, he encontrado que si se quiere hacer algo de validación en varios campos, incluso si están identificados como se requiere = verdad, cuando se reemplaza el método clean() en su forma, si los campos que desea validar no están completos al enviarlos e intenta acceder a ellos como cleaned_data["field_name"] su código explotará con un KeyError. Para evitar esto, solo acceda al campo en datos_limpios a través del método del diccionario get() y verifique si es Ninguno, o pase un valor predeterminado. Como corolario:

my_field = cleaned_data.get("field_name") # This is safe and it will work! :) 
my_filed = cleaned_data["field_name"] # This will crash when the field was not filled! :(

espero que esto ayude a alguien más, he perdido una gran cantidad de tiempo a causa de este disparate!

+0

Esta debería ser la respuesta – Gnoliz

Cuestiones relacionadas