Django User Registeration - User Edit - Password Reset

Print

In this post, we will actually implement 3 different things including User Registration, User Profile Edit and User Password Reset. We need 3 different forms for these functionalities and I will start by creating these forms.

My forms will inherit from Django Forms named  UserCreationForm, UserChangeForm, PasswordChangeForm .

REGISTRATION:

Open forms.py and import UserCreationForm

The form I am creating inherits from UserCreationForm.

I created MyDateInput because I want to use a datepicker on my form for the birthdate field.

Also I want to use radio selection for Sex(Gender) selection, Therefore I created SexOptions.

from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import User

class MyDateInput(forms.DateInput):
    input_type = 'date'


class UserCreationForm(UserCreationForm):
    #Options For User Roles
    Dispatcher = 'Dispatcher'
    Operator = 'Operator'
    Manager = 'Manager'
    RoleOptions =((Dispatcher, u'Dispatcher'), (Operator, u'Operator'), (Manager, u'Manager'))
    #Options For User Gender
    M='Male'
    F='Female'
    SexOptions =((M, u'Male'), (F, u'Female'))
    email = forms.EmailField(label="", widget=forms.TextInput(attrs={'class':'form-control', 'placeholder': 'Enter Your Email'}))
    first_name = forms.CharField(label="", max_length=100, widget=forms.TextInput(attrs={'class':'form-control', 'placeholder': 'Enter Your First Name'}))
    last_name = forms.CharField(label="", max_length=100, widget=forms.TextInput(attrs={'class':'form-control', 'placeholder': 'Enter Your Last Name'}))
    role = forms.ChoiceField(choices=RoleOptions, widget=forms.RadioSelect())
    birthdate = forms.DateField(widget=MyDateInput)
    sex = forms.ChoiceField(choices=SexOptions, widget=forms.RadioSelect())
    class Meta:
        model = User
        fields = ['username', 'email', 'first_name', 'last_name', 'password1', 'password2', 'birthdate', 'sex', 'department', 'role', 'subdivision'] 
    def __init__(self, *args, **kwargs):
        super(UserCreationForm, self).__init__(*args, **kwargs)
        self.fields['username'].widget.attrs['class'] = 'form-control'
        self.fields['username'].widget.attrs['placeholder'] = 'Enter a Username'
        self.fields['username'].label=''
        self.fields['username'].help_text='<div class="form-text text-muted"><small>Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.</small></div>'

        self.fields['password1'].widget.attrs['class'] = 'form-control'
        self.fields['password1'].widget.attrs['placeholder'] = 'Enter a Password'
        self.fields['password1'].label=''
        self.fields['password1'].help_text='<ul class="form-text text-muted small"><li>Your password can\'t be too similar to your other personal information.</li><li>Your password must contain at least 8 characters.</li><li>our password can\'t be a commonly used password.</li><li>Your password can\'t be entirely numeric.</li></ul>'

        self.fields['password2'].widget.attrs['class'] = 'form-control'
        self.fields['password2'].widget.attrs['placeholder'] = 'Verify the Password'
        self.fields['password2'].label=''
        self.fields['password2'].help_text='<div class="form-text text-muted"><small>Enter the same password as before, for verification.</small></div>'

 

 

Now I need to create a url for registration in urls.py

path('registeruser/', crmapp_views.registeruser, name='registeruser'),

 

 

Then create a view in views.py for registration. Import UserCreationForm from crmapp.forms

from crmapp.forms import UserCreationForm

def registeruser(request):
    if request.method == 'POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            form.save()
            user_name = form.cleaned_data['username']
            pass_word = form.cleaned_data['password1']
            user_obj = authenticate(request, username = user_name, password = pass_word)
            login(request, user_obj)
            messages.success(request, "Succesfully Registered", extra_tags='green')
            return redirect('crmapp')
    else:
        form = UserCreationForm()
    context = {'form':form}
    return render(request, 'registeruser.html', context)

 

Now we need to create a template (registeruser.html) in crmapp's template folder

{% extends 'base.html' %}

{% block title%}
    <title>Welcome Registeration Page</title>
{% endblock title%}

{% block content %}
    <h2 class="text-center">Register</h2>
    <div class="col-md-6 offset-md-3">
        <form method="POST" action="{% url 'registeruser' %}">
            {% csrf_token %}
            {% if form.errors %}
                <div class="alert alert-warning" role="alert">
                <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                <span aria-hidden="true">&times;</span>
                </button>
                <p>Your Form has errors</p>
                </div>  
            {% endif %}
            {{form.as_p}}
            <input type="submit" value="Register" class="btn btn-secondary mb-2">
        </form>
    </div>
{% endblock content %}

 

In our Navbar we have a button for registration already, we just need to give a link to registeruser.

<a class="btn btn-primary ml-2 mr-2" href="/{% url 'registeruser' %}">Register</a>  

 

 

 

 

This is how it looks:

 

 

To test create a few accounts and see if there are any problems. I succesfullt created these 3 users.

 

 

 

USER PROFILE EDIT:

Let's create our form first to edit user profiles.

Open forms.py and import  UserChangeForm. User change form has a default message for changing password. Here I change it to a shorter message. (Click here to reset your password)

class UserChangeForm(UserChangeForm):
    email = forms.EmailField(max_length=100,widget=forms.TextInput(attrs={'class':'form-control'}))
    first_name = forms.CharField( max_length=100, widget=forms.TextInput(attrs={'class':'form-control'}))
    last_name = forms.CharField(max_length=100, widget=forms.TextInput(attrs={'class':'form-control'}))

    class Meta:
        model = User
        fields = ['username', 'first_name', 'last_name', 'email']
    def __init__(self, *args, **kwargs):
        super(UserChangeForm, self).__init__(*args, **kwargs)
        self.fields['username'].widget.attrs['class'] = 'form-control'
        self.fields['username'].help_text='<div class="form-text text-muted"><small>Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.</small></div>'
        self.fields['password'].help_text= "Click <a href=\"../changepassword/\"> Here</a to reset your Password."


 

 Create a url in urls.py.

path('editprofile/', crmapp_views.editprofile, name='editprofile'),

 

Give a link on the NavBar. I will add a menu link for Edit Profile just after My Tasks menu link.

        <ul class="navbar-nav">
            <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                {{user.username}}
            </a>
            <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                <a class="dropdown-item" href="#">My Tasks</a>
                <a class="dropdown-item" href="/{% url 'editprofile' %}">Edit Profile</a>
                <div class="dropdown-divider"></div>
                <a class="dropdown-item" href="/{% url 'logoutuser' %}">Logout</a>
            </div>
            </li>
        </ul>

 

 

We need to create a view. Import UserChangeForm from crmapp and create a view named editprofile in views.py

from crmapp.forms import UserCreationForm, UserChangeForm


def editprofile(request):
    if request.method == "POST":
        form = UserChangeForm(request.POST, instance=request.user)
        if form.is_valid():
            form.save()
            messages.success(request, ("Your Profile Updated"))
            return redirect('crmapp')
    else:
        form = UserChangeForm(instance=request.user)
    context = {'form': form}
    return render(request, 'editprofile.html', context)

 

 

And Finally create a template (editprofile.html) for it.

{% extends 'base.html' %}

{% block title%}
    <title>Welcome Profile Edit Page</title>
{% endblock title%}

{% block content %}
    <h2 class="text-center">Edit Profile</h2>
    <div class="col-md-6 offset-md-3">
        <form method="POST" action="{% url 'editprofile' %}">
            {% csrf_token %}
            {% if form.errors %}
                <div class="alert alert-warning" role="alert">
                <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                <span aria-hidden="true">&times;</span>
                </button>
                <p>Your Form has errors</p>
                </div>
            {% endif %}
            {{form.as_p}}
            <input type="submit" value="Change" class="btn btn-secondary mb-2">
        </form>
    </div>
{% endblock content %}

 

 

 

 

 

PASSWORD RESET

Open forms.py and import  PasswordChangeForm and create a new for form from PasswordChangeForm 

from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm, PasswordChangeForm
from .models import User

class PasswordChangeForm(PasswordChangeForm):

    def __init__(self, *args, **kwargs):
        super(PasswordChangeForm, self).__init__(*args, **kwargs)
        self.fields['old_password'].widget.attrs['class'] = 'form-control'
        self.fields['new_password1'].widget.attrs['class'] = 'form-control'
        self.fields['new_password2'].widget.attrs['class'] = 'form-control'

 

In views.py, import PasswordChangeForm

from crmapp.forms import UserCreationForm, UserChangeForm, PasswordChangeForm

Create a view in views.py

def changepassword(request):
    if request.method == "POST":
        form = PasswordChangeForm(data=request.POST, user=request.user)
        if form.is_valid():
            form.save()
            messages.success(request, "Your Password Changed", extra_tags='green')
            return redirect('crmapp')
    else:
        form = PasswordChangeForm(user=request.user)
    context = {'form': form}
    return render(request, 'changepassword.html', context)

 

Create a url in urls.py

path('changepassword/', crmapp_views.changepassword, name='changepassword'),

 

Create a link on the Navbar (base.html) for changepassword url

        <ul class="navbar-nav">
            <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                {{user.username}}
            </a>
            <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                <a class="dropdown-item" href="#">My Tasks</a>
                <a class="dropdown-item" href="/{% url 'editprofile' %}">Edit Profile</a>
                <a class="dropdown-item" href="/{% url 'changepassword' %}">Reset Password</a>
                <div class="dropdown-divider"></div>
                <a class="dropdown-item" href="/{% url 'logoutuser' %}">Logout</a>
            </div>
            </li>
        </ul>

 

 

Create a template (changepassword.html) in crmapp's template folder

{% extends 'base.html' %}

{% block title%}
    <title>Welcome Change Password Page</title>
{% endblock title%}

{% block content %}
    <h2 class="text-center">Change Password</h2>
    <div class="col-md-6 offset-md-3">
        <form method="POST" action="{% url 'changepassword' %}">
            {% csrf_token %}
            {% if form.errors %}
                <div class="alert alert-warning" role="alert">
                <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                <span aria-hidden="true">&times;</span>
                </button>
                <p>Your Form has errors</p>
                </div>
            {% endif %}
            {{form.as_p}}
            <input type="submit" value="Change Password" class="btn btn-secondary mb-2">
        </form>
    </div>
{% endblock content %}

 

 This is how Navbar looks now

 

 

and our password change form

 

 

After changing the password, it logs off the user by default. You might want to keep this behavior or you may want to keep the user logged on. I want my users stay logged on after they change the password. To do that, I will import, update_session_auth_hash in views.py first.

from django.contrib.auth import authenticate, login, logout, update_session_auth_hash

 

Then modify the changepassword view like this

def changepassword(request):
    if request.method == "POST":
        form = PasswordChangeForm(data=request.POST, user=request.user)
        if form.is_valid():
            form.save()
            update_session_auth_hash(request, form.user)
            messages.success(request, "Your Password Changed", extra_tags='green')
            return redirect('crmapp')
    else:
        form = PasswordChangeForm(user=request.user)
    context = {'form': form}
    return render(request, 'changepassword.html', context)

 

That'a all.