Python 如何在Django 1.9中实现密码更改表单

Python 如何在Django 1.9中实现密码更改表单,python,django,django-users,Python,Django,Django Users,我的python项目的url如下: 我正在尝试实现密码更改表单,以便用户可以更改其密码。我如何实现它?应用程序应跟踪以前的密码,并且不应允许用户使用以前使用的密码。另外,我想实现重置密码功能 您可以查看以下文档中的更改密码部分。 它的工作原理如下: 导航到位于manage.py文件的项目 $python manage.py shell 执行以下操作: from django.contrib.auth.models import User u = User.objects.get(usernam

我的python项目的url如下:


我正在尝试实现密码更改表单,以便用户可以更改其密码。我如何实现它?应用程序应跟踪以前的密码,并且不应允许用户使用以前使用的密码。另外,我想实现重置密码功能

您可以查看以下文档中的更改密码部分。 它的工作原理如下:

  • 导航到位于
    manage.py
    文件的项目

  • $python manage.py shell

  • 执行以下操作:

    from django.contrib.auth.models import User
    u = User.objects.get(username__exact='john')
    u.set_password('new password')
    u.save()
    
  • 您必须创建一个表单集,并在提交表单时执行此操作

    您还可以使用简单的
    manage.py
    命令:

    manage.py changepassword*用户名*

    只需输入两次新密码

    对于问题的第二部分(用户不能选择旧密码),您可以创建一个表,在其中存储用户的旧密码。当用户输入新密码时,您可以在该表中检查该密码,无论他是否可以选择该密码。Django有一个用于比较两个密码的函数。

    如果您查看 您会注意到,password\u reset采用了一个名为template\u name的命名参数

    因此,使用类似URL.py的

    from django.conf.urls.defaults import *
    from django.contrib.auth.views import password_reset
    urlpatterns = patterns('',
     (r'^/accounts/password/reset/$', password_reset, {'template_name': 'my_templates/password_reset.html'}),
     ...
    
    django.contrib.auth.views.password\u reset将为匹配'/accounts/password/reset'的URL调用,其关键字参数为template\u name='my\u templates/password\u reset.html'。

    我强烈建议您浏览以下链接

    由于您使用的是自定义用户模型,因此实现该功能的一个好方法是创建一个新表单
    ChangePassword

    class ChangePassword(forms.Form):
          old_password=forms.PasswordField()
          new_password=forms.PasswordField()
          reenter_password=forms.PasswordField()
          def clean(self):
              new_password=self.cleaned_data.get('new_password')
              reenter_password=self.cleaned_data.get('reenter_password')
              #similarly old_password
             if new_password and new_password!=reenter_password or new_password==old_password:
                    #raise error
             #get the user object and check from old_password list if any one matches with the new password raise error(read whole answer you would know) 
             return self.cleaned_data #don't forget this.
    
    您可以定义
    clean()
    来检查两个密码是否匹配,以及输入的新密码是否与旧密码不同

    如果您不想让用户使用他们在启用选项之前使用过的密码

  • 创建新字段(如果要将这些密码存储为普通字符串)
  • 创建一个包含哈希先前密码的模型(为了更好的安全性)
  • 根据您的型号,您没有加密密码,因此选项1对您有好处。若要加密,可以选择sha256,库为passlib;只需搜索谷歌

    要实现选项1,只需在模型中添加一个字段,只要更改密码,就可以将旧密码附加到此字段内容。您可以使用
    CharField
    ,但其最大长度仅为255。您可以选择
    textfield
    ,对于您的型号,它如下所示:

    class Members(models.Model):
           #rest fields..
           old_passwords=models.TextField(blank=True,default='')
    
    现在,在保存ChangePassword时,请使用清理后的数据更新成员密码:

    def change_password(request):
             if request.method=='POST':
                form=ChangePassword(request.POST)
                if form.is_valid():
                      new_pass=form.cleaned_data['new_password']
                      #get the current user object as user
                      if user.old_password=='':
                             #it's first time user is changing password
                             #populate our Members old_password_field
                             user.old_password=user.password
                      else:         
                             user.old_password=user.old_password+','+user.password
                      user.password=new_password 
                      user.save()
                      #do whatever you want to do man..
    

    代码只是帮助你理解你需要做什么,你必须用自己的方式去做

    为什么不使用django内置的PasswordChangeForm(django.contrib.auth.forms)

    如果您喜欢它的工作方式,只需从中使用它,或者您可以创建一个继承PasswordChangeForm的新的

        class PasswordChangeCustomForm(PasswordChangeForm):
            error_css_class = 'has-error'
            error_messages = {'password_incorrect':
                      "Το παλιό συνθηματικό δεν είναι σωστό. Προσπαθείστε   ξανά."}
            old_password = CharField(required=True, label='Συνθηματικό',
                          widget=PasswordInput(attrs={
                            'class': 'form-control'}),
                          error_messages={
                            'required': 'Το συνθηματικό δε μπορεί να είναι κενό'})
    
            new_password1 = CharField(required=True, label='Συνθηματικό',
                          widget=PasswordInput(attrs={
                            'class': 'form-control'}),
                          error_messages={
                            'required': 'Το συνθηματικό δε μπορεί να είναι κενό'})
            new_password2 = CharField(required=True, label='Συνθηματικό (Επαναλάβατε)',
                          widget=PasswordInput(attrs={
                            'class': 'form-control'}),
                          error_messages={
                            'required': 'Το συνθηματικό δε μπορεί να είναι κενό'})
    
    稍后我将提供一个clean和save方法的示例

    有关更多详细信息,请参见

    from django.contrib.auth.forms import PasswordChangeForm
    
    
    
    然后

    在你看来

    def get(self,request):
    实例\用户=获取\对象\或\ 404(用户,id=int(用户\ id))
    表单\编辑\密码=MyChangeFormPassword(实例\用户)
    上下文={'form_edit_password':form_edit_password}
    返回渲染(请求、self.template\u名称、上下文)
    
    在模板上

    
    {{form_edit_password.old_password}}
    {{form_edit_password.new_password1}}
    {{form_edit_password.new_password2}}
    
    你的职位呢

    form_edit_password = ChangePasswordForm(user, data=put)
    if form_edit_password.is_valid():
        form_edit_password.save()
        return self.__succes_response(_('Password updated'))
    else:
        return self.__error_response([form_edit_password])
    
    Django会为你做一切的,疯了吧?您可以在MyChangeFormPassword上编写自己的规则,覆盖父方法,但这是一个很好的方法

    我是为Django 3写这篇文章的。

    在url.py中

    path('password-reset/', views.ChangePassword.as_view(), name='password-reset'),
    
    密码更改表格:

    class MyPasswordChangeForm(PasswordChangeForm):
        def __init__(self, user, *args, **kwargs):
            self.user = user
            super().__init__(user, *args, **kwargs)
            self.fields['old_password'].widget.attrs.update({'class': 'form-control', 'placeholder': "Old Password"})
            self.fields['new_password1'].widget.attrs.update({'class': 'form-control', 'placeholder': "New Password"})
            self.fields['new_password2'].widget.attrs.update({'class': 'form-control', 'placeholder': "New Password"})
    
        def save(self, commit=True):
            password = self.cleaned_data["new_password1"]
            self.user.set_password(password)
            if commit:
                self.user.save()
            return self.user
    
    在views.py中:

    from django.views.generic import TemplateView
    from django.contrib.auth.mixins import LoginRequiredMixin
    
    class ChangePassword(LoginRequiredMixin,TemplateView):
    
        def get(self, request, *args, **kwargs):
            form_class = MyPasswordChangeForm
            form = self.form_class(self.request.user)
            return render(request, 'password.html',{'form': form,})
    
        def post(self, request, *args, **kwargs):
            form = self.form_class(request.user, request.POST)
            if form.is_valid():
                user = form.save()
                update_session_auth_hash(request, user)  # Important!
                return render(request, 'password.html', {'form': form, 'password_changed': True})
            else:
                return render(request, 'password.html', {'form': form, 'password_changed': False})
    
    在password.html中:

        <div id='PasswordChnageForm'>
            <form method="post" action="{% url 'password-reset' %}">
            {% csrf_token %}
                {% for field in form %}
                        {{ field }}
                        {% if field.help_text %}
                            <small style="display: none">{{ field.help_text }}</small>
                        {% endif %}
                        {% for error in field.errors %}
                            <p style="color: red">{{ error }}</p>
                        {% endfor %}
        
                {% endfor %}
                    <input type="submit" name="save" value="Save" >
             </form>
        </div>
        <script src="{% static 'web_admin/js/jquery-3.4.1.min.js' %}"></script>
        <script>
            $("#CallPasswordChangeButton").on('click', function (e) {
                e.preventDefault(); // avoid to execute the actual submit of the form.
                var form = $('#PasswordChnageForm');
                $.ajax({
                    type: 'Post',
                    url: "{% url 'password-reset' %}",
                    data: form.serialize(),
                    success: function (data) {
                        $('#password_change').empty().html(data);
                    }
                });
            });
        </script>
    
    
    {%csrf_令牌%}
    {%形式的字段为%}
    {{field}}
    {%if field.help_text%}
    {{field.help_text}
    {%endif%}
    {%字段中有错误。错误%}
    

    {{error}

    {%endfor%} {%endfor%} $(“#CallPasswordChangeButton”)。在('click',函数(e){ e、 preventDefault();//避免执行表单的实际提交。 var form=$(“#PasswordChnageForm”); $.ajax({ 键入:“Post”, url:“{%url'密码重置“%}”, 数据:form.serialize(), 成功:功能(数据){ $('#密码_更改').empty().html(数据); } }); });
    So template\u name-应该是我重置密码的自定义模板吗?您提供的链接是否足以使用示例模板?您是指旧的\u password=forms.PasswordInput()?因为我的无法解决你的问题,“用户”在这里是什么意思?我需要创建一个单独的类来存储用户吗?另外,“return self.cleaned_data”给了我“return out of function”是的,它是forms.PasswordInput(),用户对象意味着你的成员的类对象,return应该可以很好地工作。试着从这里读取这似乎并不能回答问题。OP希望有一个更改密码表单(和视图/模板),以及密码历史记录。@GregSchmit在我看来,他询问的功能的答案将非常长。这就是为什么我没有写完整的代码。相反,我写了他如何解决他的问题。我同意这是一个宽泛的、不恰当的问题。
    from django.views.generic import TemplateView
    from django.contrib.auth.mixins import LoginRequiredMixin
    
    class ChangePassword(LoginRequiredMixin,TemplateView):
    
        def get(self, request, *args, **kwargs):
            form_class = MyPasswordChangeForm
            form = self.form_class(self.request.user)
            return render(request, 'password.html',{'form': form,})
    
        def post(self, request, *args, **kwargs):
            form = self.form_class(request.user, request.POST)
            if form.is_valid():
                user = form.save()
                update_session_auth_hash(request, user)  # Important!
                return render(request, 'password.html', {'form': form, 'password_changed': True})
            else:
                return render(request, 'password.html', {'form': form, 'password_changed': False})
    
        <div id='PasswordChnageForm'>
            <form method="post" action="{% url 'password-reset' %}">
            {% csrf_token %}
                {% for field in form %}
                        {{ field }}
                        {% if field.help_text %}
                            <small style="display: none">{{ field.help_text }}</small>
                        {% endif %}
                        {% for error in field.errors %}
                            <p style="color: red">{{ error }}</p>
                        {% endfor %}
        
                {% endfor %}
                    <input type="submit" name="save" value="Save" >
             </form>
        </div>
        <script src="{% static 'web_admin/js/jquery-3.4.1.min.js' %}"></script>
        <script>
            $("#CallPasswordChangeButton").on('click', function (e) {
                e.preventDefault(); // avoid to execute the actual submit of the form.
                var form = $('#PasswordChnageForm');
                $.ajax({
                    type: 'Post',
                    url: "{% url 'password-reset' %}",
                    data: form.serialize(),
                    success: function (data) {
                        $('#password_change').empty().html(data);
                    }
                });
            });
        </script>