2011-01-27 5 views
17

다음 양식이 있습니다. 어떻게하면 사용자가 자신의 emailadsress를 마지막으로 변경할 수 있기 전에 사용자의 암호를 다시 확인할 수 있습니까? 그는 로그인되어 있어도, 나는 그것이 정말로 사용자인지 확실히하고 싶다. 그냥 securtiy 것.사용자의 check_password()가 다시

.check_password()으로 어떻게해야합니까?

'EmailChangeForm' object has no attribute 'user' 

    /home/craphunter/workspace/project/trunk/project/auth/user/email_change/forms.py in clean_password, line 43 

from django import forms 
from django.db.models.loading import cache 
from django.utils.translation import ugettext_lazy as _ 
from django.contrib.auth.models import User 


class EmailChangeForm(forms.Form): 

    email = forms.EmailField(label='New E-mail', max_length=75) 
    password = forms.CharField(widget=forms.PasswordInput) 

    def __init__(self, user, *args, **kwargs): 
     super(EmailChangeForm, self).__init__(*args, **kwargs) 
     self.user = user 

    def clean_password(self): 
     valid = self.user.check_password(self.cleaned_data['password']) 
     if not valid: 
      raise forms.ValidationError("Password Incorrect") 
     return valid 

    def __init__(self, username=None, *args, **kwargs): 
     """Constructor. 

     **Mandatory arguments** 

     ``username`` 
      The username of the user that requested the email change. 

     """ 
     self.username = username 
     super(EmailChangeForm, self).__init__(*args, **kwargs) 

    def clean_email(self): 
     """Checks whether the new email address differs from the user's current 
     email address. 

     """ 
     email = self.cleaned_data.get('email') 

     User = cache.get_model('auth', 'User') 
     user = User.objects.get(username__exact=self.username) 

     # Check if the new email address differs from the current email address. 
     if user.email == email: 
      raise forms.ValidationError('New email address cannot be the same \ 
       as your current email address') 

     return email 

답변

17

나는 이런 식으로 뭔가를보고 코드를 리팩토링 것 :

보기 :

def send_email_change_request(user, new_email, https=True): 

    site = cache.get_model('sites', 'Site') 

    email = new_email 
    verification_key = generate_key(user, email) 

    current_site = Site.objects.get_current() 
    site_name = current_site.name 
    domain = current_site.domain 

    protocol = 'https' if https else 'http' 

    # First clean all email change requests made by this user 
    qs = EmailChangeRequest.objects.filter(user=request.user) 
    qs.delete() 

    # Create an email change request 
    change_request = EmailChangeRequest(
     user = request.user, 
     verification_key = verification_key, 
     email = email 
    ) 
    change_request.save() 

    # Prepare context 
    c = { 
     'email': email, 
     'site_domain': 'dev.tolisto.de', 
     'site_name': 'tolisto', 
     'user': self.user, 
     'verification_key': verification_key, 
     'protocol': protocol, 
    } 
    c.update(extra_context) 
    context = Context(c) 

    # Send success email 
    subject = "Subject" # I don't think that using template for 
         # subject is good idea 
    message = render_to_string(email_message_template_name, context_instance=context) 

    send_mail(subject, message, None, [email]) 
:보기에서

class EmailChangeForm(Form): 
    email = ... 
    old_password = CharField(..., widget=Password()) 

    def __init__(self, user, data=None): 
     self.user = user 
     super(EmailChangeForm, self).__init__(data=data) 

    def clean_old_password(self): 
     password = self.cleaned_data.get('password', None) 
     if not self.user.check_password(password): 
      raise ValidationError('Invalid password') 

추출 로직 :

@login_required 
def view(request, extra_context=None, ...): 

    form = EmailChangeForm(user=request.user, data=request.POST or None) 

    if request.POST and form.is_valid(): 
     send_email_change_request(request.user, 
            form.cleaned_data['email'], 
            https=request.is_secure()) 
     return redirect(success_url) 
    ... 

암호 검증 형태로 이동

복잡한 내용을보기 내부에 넣지 마십시오 (예 : 전자 메일 렌더링 및 전송).

+0

고마워. 그것은 역시 도움이되었다! – craphunter

9

당신이 당신의 자신의 질문에 대답 같은 느낌 :)이 check_password 방법에

워드 프로세서 현재 위치 : http://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.models.User.check_password

success = user.check_password(request.POST['submitted_password']) 
if success: 
    # do your email changing magic 
else: 
    return http.HttpResponse("Your password is incorrect") 
    # or more appropriately your template with errors 

이미에 request.user 전달하고 있기 때문에 양식 생성자 (자신의 이유로 __init__을 재정의 한 것처럼 보임) 모든 논리를 아무런 문제없이 양식에 넣을 수 있습니다.

class MyForm(forms.Form): 
    # ... 
    password = forms.CharField(widget=forms.PasswordInput) 

    def __init__(self, user, *args, **kwargs): 
      super(MyForm, self).__init__(*args, **kwargs) 
      self.user = user 

    def clean_password(self): 
     valid = self.user.check_password(self.cleaned_data['password']) 
     if not valid: 
      raise forms.ValidationError("Password Incorrect") 
     return valid 

갱신 양식을

확인을보고 난 후에. 주된 문제는 __init__이 두 번 정의되어 첫 번째 문을 쓸모 없게 만드는 것입니다. 두 번째로 볼 수있는 문제는 우리가 실제로 할 필요가없는 user에 대한 여러 쿼리를 수행한다는 것입니다.

원래 질문에서 벗어났습니다.하지만이 학습 경험은 유용 할 것입니다.

  • 우리가 '이후 username
  • User.objects.get(username=username)에 대한 쿼리를 제거 텍스트 대신 User 인스턴스를 받아 __init__을 변경 추가 __init__ 정의를 제거

    • :

      나는 단지 몇 가지를 변경했습니다 다시 사용자 객체를 전달합니다.

    그냥 나는 이동에 대한 Skirmantas의 제안을 통해 다음과 같은 권하고 싶습니다, 우리가 여기서 좋은 방법에 대해 얘기하고 마지막으로 이후 username=request.user.username

    class EmailChangeForm(forms.Form): 
        email = forms.EmailField(label='New E-mail', max_length=75) 
        password = forms.CharField(widget=forms.PasswordInput) 
    
        def __init__(self, user=None, *args, **kwargs): 
         self.user = user 
         super(EmailChangeForm, self).__init__(*args, **kwargs) 
    
        def clean_password(self): 
         valid = self.user.check_password(self.cleaned_data['password']) 
         if not valid: 
          raise forms.ValidationError("Password Incorrect") 
    
        def clean_email(self): 
         email = self.cleaned_data.get('email') 
    
         # no need to query a user object if we're passing it in anyways. 
         user = self.user 
    
         # Check if the new email address differs from the current email address. 
         if user.email == email: 
          raise forms.ValidationError('New email address cannot be the same \ 
           as your current email address') 
    
         return email 
    

    대신 폼 생성자 user=request.user을 통과 기억 현재보기 코드를 양식 메소드에 연결하면 myform.send_confirmation_email으로 간단하게 호출 할 수 있습니다.

    소리가 좋은 운동입니다!

  • +0

    감사합니다. 예, 저는 장고에있는 초보자입니다 ... 때로는 해결책이 너무 간단합니다. – craphunter

    +0

    문제가없는 사람입니다! 예, 저는 장고와 파이썬을 좋아합니다. 오, 그거 알아? 간소화하기 위해 이미 사용자 객체를 전달하고 있기 때문에 양식에 비밀번호 필드를 추가해야합니다. 그냥'password = forms.CharField (widget = forms.PasswordInput))'을 정의하고'clean_password'를 오버라이드하여 암호 검사를 수행하십시오. 그렇게하면 오류 양식을 다시 표시하기위한 양식 프레임 워크에 머물 수 있습니다. –

    +0

    clean_password는 무엇을 의미합니까? 비밀번호에 타이핑 오류가 있습니까?})? – craphunter

    1

    다시 Yuji에게 감사드립니다. 그것은 내가 처음으로 변수 사용자가 없을 때 작동합니다. 나는 또한 def clean_password 처음 두 줄을 def clean_email에 추가했습니다.

    from django import forms 
    from django.db.models.loading import cache 
    from django.utils.translation import ugettext_lazy as _ 
    from django.contrib.auth.models import User 
    
    
    class EmailChangeForm(forms.Form): 
    
        email = forms.EmailField(label='New E-mail', max_length=75) 
        password = forms.CharField(widget=forms.PasswordInput) 
    
        def __init__(self, *args, **kwargs): 
         self.user = user 
         super(EmailChangeForm, self).__init__(*args, **kwargs) 
    
        def clean_password(self): 
         User = cache.get_model('auth', 'User') 
         user = User.objects.get(username__exact=self.username) 
         valid = user.check_password(self.cleaned_data['password']) 
         if not valid: 
          raise forms.ValidationError("Password Incorrect") 
         return valid 
    
        def __init__(self, username=None, *args, **kwargs): 
         """Constructor. 
    
         **Mandatory arguments** 
    
         ``username`` 
          The username of the user that requested the email change. 
    
         """ 
         self.username = username 
         super(EmailChangeForm, self).__init__(*args, **kwargs) 
    
        def clean_email(self): 
         """Checks whether the new email address differs from the user's current 
         email address. 
    
         """ 
         email = self.cleaned_data.get('email') 
    
         User = cache.get_model('auth', 'User') 
         user = User.objects.get(username__exact=self.username) 
    
         # Check if the new email address differs from the current email address. 
         if user.email == email: 
          raise forms.ValidationError('New email address cannot be the same \ 
           as your current email address') 
    
         return email 
    
    +0

    축하합니다! 그러나 사용자가 2 일 수 있기 때문에 사용자에 대해 2 개의 쿼리를 수행하고 있으므로 업데이트 된 답변을 살펴보십시오! 좋은 운동이 될 수 있습니다 :) –

    +0

    포틀랜드에 다시 한 번 감사드립니다. 나는 너의 충고를했는데 일하고있다! 나는 자러 간다! 독일에서는 아침 2시입니다! 좋은 저녁 되세요! – craphunter