تغيير اللغه الي العربية

My Blog


All posts

Use Django's Authentication App part 3.

we will continue and create profile pages, profile home and edit profile page.

but first let's include the django passwords urls, we will use it later.

if you didn't read part 1 and part 2 you should read them first.

In users app we will create folder called passwords and inside it will create file urls.py and paste these urls in it.


# users/passwords/urls.py
from django.contrib.auth import views
from django.urls import path

urlpatterns = [
path('password_change/', views.PasswordChangeView.as_view(),
name='password_change'),
path('password_change/done/', views.PasswordChangeDoneView.as_view(),
name='password_change_done'),
path('password_reset/', views.PasswordResetView.as_view(),
name='password_reset'),
path('password_reset/done/', views.PasswordResetDoneView.as_view(),
name='password_reset_done'),
path('reset/<uidb64>/<token>/', views.PasswordResetConfirmView.as_view(),
name='password_reset_confirm'),
path('reset/done/', views.PasswordResetCompleteView.as_view(),
name='password_reset_complete'),
]

These are the django passwords built-in views for reset and change passwords.
we will also need to create an __init__.py file inside passwords folder to mark it as a Python package.

And we will include this file into our main urls.

# django_tips/urls.py
from django.contrib import admin
from django.urls import path, include


urlpatterns = [
path('admin/', admin.site.urls),
path("", include("users.urls")),
path("accounts/", include("users.passwords.urls")),
]


Now let's create User Home View and User Update View.
in users app edit the views.py

# users/views.py
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.urls import reverse_lazy
from django.views.generic import DetailView, UpdateView

from .forms import UserDetailChangeForm


class UserHomeView(LoginRequiredMixin, DetailView):
"""User Profile Page"""

template_name = "user/home.html"

def get_object(self):
return self.request.user


class UserUpdateView(SuccessMessageMixin, LoginRequiredMixin, UpdateView):
"""User Profile Edit Page"""

form_class = UserDetailChangeForm
template_name = "user/user_edit.html"
success_url = reverse_lazy("users:user_profile")
success_message = "Details successfully updated"

def get_object(self):
return self.request.user

We will use DetailView to show user details and UpdateView to update user details.
we also used LoginRequiredMixin to make sure these pages only appear to logged in users.
and the SuccessMessageMixin to show a success message after user successfully update his account.

let's create the UserDetailChangeForm we used in the UserUpdateView
in the forms.py add this.

# users/forms.py 
...
...

class UserDetailChangeForm(forms.ModelForm):
class Meta:
model = User
fields = ["username", "email", "first_name", "last_name"]

def clean_email(self):
email = self.cleaned_data["email"]
if email:
match = User.objects.filter(email=email).exclude(id=self.instance.pk)
if match:
raise forms.ValidationError("This email address is already in use")
return email

Like we did before in the admin forms we checked the email if it exists.

You can read the post about checking email here


Now we will add the views to the urls.py in users app

# users/urls.py
from django.contrib.auth import views as django_views
from django.urls import path

from . import views

app_name = "users"


urlpatterns = [
path("profile/", views.UserHomeView.as_view(), name="user_profile"),
path("details/", views.UserUpdateView.as_view(), name="account_update"),
path("logout/", django_views.LogoutView.as_view(), name="logout"),
path("login/", django_views.LoginView.as_view(), name="login"),
]


Now let's create our templates.
we will create a lot of templates here so stay focused.

first our Home View and Update view templates will be in this path templates/user/
we will create home.html and user_edit.html
and Django passwords views templates will be in this path templates/registration

this will be our folder
structure for registration
templates/registration
            |__ password_change_done.html
            |__ password_change_form.html
            |__ password_reset_complete.html
            |__ password_reset_confirm.html
            |__ password_reset_done.html
            |__ password_reset_email.html
            |__ password_reset_form.html


Make sure to create templates with the exact names because that's where the view will look for by default.
I got the template names from django source code at
django/contrib/admin/templates/registration/
we will override them because we don't want normal users to see admin pages.

so our final project structure will be like this.

|__ Django_Tips_Project
|ــ django_tips
|ــ __init__.py
|ــ asgi.py
|ــ settings.py
|ــ urls.py
|ــ wsgi.py
|ــ templates
|ــ registration
|ــ login.html
|__ password_change_done.html
|__ password_change_form.html
|__ password_reset_complete.html
|__ password_reset_confirm.html
|__ password_reset_done.html
|__ password_reset_email.html
|__ password_reset_form.html
|__ user
|__ home.html
|__ user_edit.html
|ــ base.html
|__ users
|__ migrations
|__ passwords
|__ __init__.py
|__ urls.py
|__ __init__.py
|__ admin.py
|__ apps.py
|__ forms.py
|__ models.py
|__ urls.py
|__ views.py
|__ db.sqlite3
|__ manage.py
|__ requirements.txt

Now let's edit our templates.
first we will add link to password reset in login.html
# registration/login.html
...
...
<a href="{% url 'password_reset' %}">Forgotten password?</a>

Now edit the rest of the templates like this.

# user/home.html
{% extends 'base.html' %}
{% block title %}
| My account
{% endblock %}
{% block content %}


<div>
{% if messages %}
{% for message in messages %}
<ul>
<li>{{ message }}</li>
</ul>
{% endfor %}
{% endif %}
<h1>Account <a href="{% url 'users:account_update' %}">Edit</a></h1>
<div>
<p>Username: {{ user.username }}</p>
<p>Email: {% if user.email %}{{ user.email }}{% else %}<span>not specified</span>{% endif %}
</p>
<p>First name:
{% if user.first_name %}{{ user.first_name }}{% else %}<span>not specified</span>{% endif %}
</p>
<p>Last name:
{% if user.last_name %}{{ user.last_name }}{% else %}<span>not specified</span>{% endif %}
</p>
</div>
</div>

{% endblock %}

# user/user_edit.html
{% extends 'base.html' %}
{% block title %}
Edit account
{% endblock %}
{% block content %}

<div>
<h1>Edit account</h1>
<div>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}<br>
<p>Password:<br> <a href="{% url 'password_change' %}">click to change password</a></p>
<button type="submit">Save</button>
<a href="{% url 'users:user_profile' %}">Back}</a>
</form>
</div>
</div>


{% endblock %}

# registration/password_change_done.html
{% extends "base.html" %}
{% block title %}
Password change
{% endblock %}
{% block content %}


<h1>Your password has been changed successfully</h1>
<a href="{% url 'users:user_profile' %}">Go to your profile</a>

{% endblock %}

# registration/password_change_form.html
{% extends "base.html" %}
{% block title %}
Password change
{% endblock %}

{% block content %}

<div>
<h4>Password change</h4>
<form method="POST" action="">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Save</button>
<a href="{% url 'users:account_update' %}">Back</a>
</form>
</div>
{% endblock %}

# registration/password_reset_complete.html
{% extends "base.html" %}
{% block title %}Forgotten password?{% endblock %}
{% block content %}
<div>
<div>
{% if user.is_authenticated %}
<div>
<p>You are logged in</p>
<a href="/">Home Page</a>
</div>
{% else %}
<h2>Forgotten password?</h2>
<div>
<h1>Password Successfully Reseted.</h1>
</div>
{% endif %}
</div>
</div>

{% endblock %}

# registration/password_reset_confirm.html
{% extends "base.html" %}
{% block title %}Forgotten password?{% endblock %}
{% block content %}

<div>
<div>
{% if user.is_authenticated %}
<div>
<p>You are logged in</p>
<a href="/">Home Page</a>
</div>
{% else %}
<h2>Password change</h2>
<div>
<div>
<h3>Set your password</h3>
<hr>
{% if validlink %}
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
<a href="{% url 'users:login' %}">Back</a>
</form>
{% else %}
<form>
<p>
The password reset link was invalid, possibly because it has already been used. Please request a new password reset.
</p>
<a href="{% url 'users:login' %}">Login</a>
</form>
</div>
{% endif %}
</div>
{% endif %}
</div>
</div>
{% endblock %}


# registration/password_reset_done.html
{% extends "base.html" %}
{% block title %}Forgotten password?{% endblock %}

{% block content %}
<div>
<div>
{% if user.is_authenticated %}
<div>
<p>You are logged in</p>
<a href="/">Home Page</a>
</div>
{% else %}
<h2>Forgotten password?</h2>
<div>
<h1>Reset link sent, Please check your email.</h1>
</div>
{% endif %}
</div>
</div>
{% endblock %}


# registration/password_reset_email.html

Hello,

Reset your password on {{ domain }} for {{ user }}:
To reset your passowrd click on the link below.


{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}

{% endblock %}

Regards,
Django Tips Team
# registration/password_reset_form.html
{% extends "base.html" %}
{% block title %}Forgotten password?{% endblock %}

{% block content %}
<div>
<div>
{% if user.is_authenticated %}
<div>
<p>You are logged in</p>
<a href="/">Home Page</a>
</div>
{% else %}
<h2>Forgotten password?</h2>
<div>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
<a href="{% url 'users:login' %}">Back</a>
</form>
</div>
{% endif %}
</div>
</div>
{% endblock %}





And all is set! you can now go to /profile/ to see profile details and update it.
also at /login/ you can choose to reset your password.

For resetting password you will need to setup email service with Django like mailgun, sendgrid, gmail.
But we won't cover that here so just for testing we can use the Django console and send the email inside our terminal.

in settings.py add this

# settings.py

# Emailing system
if DEBUG:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

Now when you fill the reset form with user email the email will be in the terminal like this

Copy the link and paste it in your browser to complete testing.
Note this is the email we got in registration/password_reset_email.html you can edit it but leave variables as it is.

And we are done!

I hope the tutorial was simple.
Feel free to reach out if you have any questions.

Join to discord Server Here - Django Learn Together.





Last Updated: 1 month, 1 week ago
Views: 385