2010-08-20 32 views
13

Tôi nhận được KeyError cho 'mật khẩu' khi tôi cố gắng gửi biểu mẫu của mình.Phương pháp dọn dẹp Django ném KeyError trên POST

dấu vết:

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' 

lần xem:

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) 

hình thức:

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

bạn có thể đăng mã đang sử dụng biểu mẫu này không? –

+0

bao gồm mã xem – JPC

+0

Bạn cũng có thể đăng mã mẫu không? –

Trả lời

10

Aha! Thông báo lỗi xác thực mà bạn đang xem thực sự không phải là thông báo lỗi xác thực. Hãy để tôi giải thích. Khi bạn làm cho dụ hình thức mô hình sử dụng as_p, nó ám từng lĩnh vực theo cách sau:

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

Chuỗi Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters rằng bạn đang nhìn thấy phía bên tay phải của lĩnh vực này là gì, nhưng các văn bản giúp đỡ. Văn bản trợ giúp này được lấy từ định nghĩa mô hình - bạn có thể xác minh điều này bằng cách truy cập django/contrib/auth/models.py và kiểm tra định nghĩa của lớp User.

Khi bạn ghi đè trường username bạn bỏ qua bất kỳ văn bản trợ giúp nào. Đương nhiên là "lỗi" biến mất.

Để xác minh lý thuyết này, hãy làm như sau trong phương pháp main của bạn.

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

Cập nhật

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

Dòng này có thể gây ra rắc rối khi người dùng không cung cấp một hoặc cả hai passwordcpassword. Ví dụ: hãy thử điều này từ vỏ 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' 

Thay đổi phương thức của bạn ở dạng clean để đảm bảo cả hai giá trị đều có mặt trước khi so sánh. Một cái gì đó như thế này:

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!Điều đó làm cho một tấn ý nghĩa. Tôi sẽ không bao giờ nghĩ ra điều đó. Tôi đã nhận được kinda khó chịu với ModelForm cho người dùng vì tôi đã phải xác định lại các lĩnh vực và tôi vẫn nhận được rằng KeyError vì một lý do nào đó. Tôi đã kết thúc bằng cách sử dụng một hình thức thông thường và chỉ cần tạo User. – JPC

+0

Có thể làm cho văn bản trợ giúp biến mất mà không ghi đè không? – JPC

+0

@JPC: Bạn có thể ghi đè phương thức '__init__' của biểu mẫu và đặt' self.fields ['username']. Help_text = None'. Một IMHO crufty bit. Cách khác, bạn có thể sử dụng một phương pháp khác để hiển thị biểu mẫu nơi bạn bỏ qua văn bản trợ giúp. –

11

Từ kinh nghiệm của riêng tôi, tôi thấy rằng nếu bạn muốn làm một số xác nhận trong nhiều lĩnh vực, ngay cả khi họ được đánh dấu theo yêu cầu = True, khi bạn ghi đè lên các phương pháp clean() trong mẫu của bạn, nếu các trường bạn muốn xác thực không được điền khi gửi và bạn cố gắng nhập chúng là cleaned_data["field_name"] mã của bạn sẽ phát nổ với số KeyError. Để tránh điều này, chỉ cần truy cập trường trong clean_data thông qua phương thức từ điển get() và kiểm tra xem có Không hoặc chuyển giá trị mặc định. Là một hệ quả:

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

Tôi hy vọng điều này sẽ giúp người khác, tôi mất rất nhiều thời gian vì điều ngớ ngẩn này!

+0

Đây phải là câu trả lời – Gnoliz

Các vấn đề liên quan