Чистый метод Django, бросающий KeyError на POST - PullRequest
14 голосов
/ 20 августа 2010

Я получаю KeyError для «пароля» при попытке отправить форму.

trace:

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'

просмотров:

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)

форм:

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')

Ответы [ 2 ]

15 голосов
/ 14 марта 2013

Исходя из собственного опыта, я обнаружил, что если вы хотите провести некоторую проверку в нескольких полях, даже если они помечены как обязательные = True, когда вы переопределяете метод clean() в своей форме, если поля, которые вы хотитеvalidate не заполняются при отправке, и вы пытаетесь обработать их как cleaned_data["field_name"] ваш код взорвется с KeyError.Чтобы избежать этого, просто получите доступ к полю в cleaned_data с помощью метода словаря get() и проверьте, имеет ли значение None, или передайте значение по умолчанию.Как следствие:

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! :(

Надеюсь, это поможет кому-то еще, я потерял много времени из-за этой глупости!

10 голосов
/ 20 августа 2010

Aha! Сообщение об ошибке проверки, которое вы видите, на самом деле не является сообщением об ошибке проверки. Позволь мне объяснить. Когда вы визуализируете экземпляр формы модели, используя as_p, каждое поле отображается следующим образом:

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

Строка Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters, которую вы видите с правой стороны поля, является не чем иным, как текстом справки. Этот текст справки взят из определения модели - это можно проверить, посетив django/contrib/auth/models.py и проверив определение класса User.

При переопределении поля username вы пропускаете любой текст справки. Естественно "ошибка" исчезает.

Чтобы проверить эту теорию, выполните в своем методе 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})

Обновление

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

Эта строка может вызвать проблемы, когда пользователь не вводит один или оба из password и cpassword. Например, попробуйте это из оболочки Django:

>>> data = dict(username = 'admin', cpassword = 'foo', email='admin@bar.com')
>>> 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'

Измените метод clean вашей формы, чтобы убедиться, что оба значения присутствуют перед сравнением. Примерно так:

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")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...