1.
Install django
pip install django
- Show version of django
python -m django --version
2. Create project
django-admin startproject django_project
3. Run project
python manage.py runserver
4. Create new app
python manage.py startapp blog
- Go to view.py then import http and create a function
from django.shortcuts import render
from django.http import HttpResponse
def home(request):
return HttpResponse("<h1>Home page</h1>")
- Create urls.py file inside of blog
from django.urls import path
from . import views
urlpatterns = [
path('',views.index)
]
urls.py of django_project
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('blog/', include('blog.urls'))
]
5. Create template(for html)
- create a folder template inside of blog and inside template add
folder blog (create html files inside that)
- Add that html and before that
- INSTALLED_APPS = [
'blog.apps.BlogConfig',
And
def about(request):
return render(request,'blog/about.html')
6. Display a data from post
Views.py
from django.shortcuts import render
from django.http import HttpResponse
posts = [
{
'author' : 'Habtamu Asayto',
'title' : 'The first post',
'content' : 'The whole content of the first blog post',
'posted_date' : 'February 12, 2024'
},
{
'author' : 'Some One',
'title' : 'The second post',
'content' : 'The whole content of the 2ns blog post',
'posted_date' : 'September 12, 2025'
}
]
def index(request):
context = {
'posts' : posts
}
return render(request, 'blog/index.html', context)
def about(request):
return render(request,'blog/about.html',{'title': 'About'})
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{% if title %}
<title>Django blog {{ title }}</title>
{% else %}
<title>Django blog</title>
{% endif %}
</head>
<body>
{% for post in posts %}
<h1>{{ post.title }}</h1>
<p>By {{ post.author }} on {{ post.posted_date }}</p>
<p> {{ post.content }} </p>
{% endfor %}
</body>
</html>
About.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{% if title %}
<title>Django blog - {{ title }}</title>
{% else %}
<title>Django blog</title>
{% endif %}
</head>
<body>
<h1>About page</h1>
</body>
</html>
7. Create a base.html file used as a parent html file, then index and
about files are inheriting from base
Base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{% if title %}
<title>Django blog - {{ title }}</title>
{% else %}
<title>Django blog</title>
{% endif %}
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>
Index.html
{% extends "blog/base.html" %}
{% block content %}
{% for post in posts %}
<h1>{{ post.title }}</h1>
<p>By {{ post.author }} on {{ post.posted_date }}</p>
<p> {{ post.content }} </p>
{% endfor %}
{% endblock content %}
8. Add bootstrap and css
9. Create admin user
python manage.py createsuperuser
- There error
django.db.utils.OperationalError: no such table: auth_user
- To fix the above error, migrate
python manage.py makemigrations
python manage.py migrate
10. Database and migration
Models.py
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User # many post to one user
relationship between users and the model
class Post(models.Model):
title = models.CharField(max_length=255),
content = models.TextField(),
posted_date = models.DateTimeField(default=timezone.now),
author = models.ForeignKey(User, on_delete=models.CASCADE)
then,
python manage.py makemigrations blog
python manage.py sqlmigrate blog 0001
python manage.py migrate
python manage.py shell
from blog.models import Post
from django.contrib.auth.models import User
User.objects.all()
User.objects.first()
User.objects.filter(username='habtamu')
User.objects.filter(username='habtamu').first() # assign this to
user variable
user = User.objects.filter(username='habtamu').first()
user
user.id = user.pk
>>> user = User.objects.filter(id=1)
>>> user
Now continue to table Post
post_1 = Post(title='Blog Post 1',content='Content of blog post
1',author=user)
post_1.save()
Post.objects.all()
>>> post = Post.objects.first()
>>> port.content
>>> post.author
<User: Habtamu>
>>> post.author.email
'
[email protected]'
>>> user.post_set
>>> user.post_set.all()
>>> user.post_set.create(title='Blog Post 3', content='The content
of blog post 3')
>>> Post.objects.all()
Now, display this inserted database to views
Views.py
from .models import Post
def index(request):
context = {
'posts' : Post.objects.all()
}
return render(request, 'blog/index.html', context)
Date format
index.html
<small class="text-muted">{{ post.posted_date|date:"F d,
Y" }}</small>
Register the Post blog to admin.py
Admin.py
from django.contrib import admin
from .models import Post
admin.site.register(Post)
- To add a post inside admin of blog
Admin.py
from django.contrib import admin
from .models import Post
admin.site.register(Post)
11. Registration form
Create new users
python manage.py startapp users
then, add into INSTALLED_APPS on setting.py
'users.apps.UsersConfig',
Go to views.py and add a function register
Views.py
from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm
from django.contrib import messages
def register(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
messages.success(request,f"Account created for
{username}!")
return redirect('blog-home')
else:
form = UserCreationForm()
return render(request, 'users/register.html', {'form':form})
register.html
{% extends "blog/base.html" %}
{% block content %}
<div class="content-section">
<form method="post">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">
Signup here
</legend>
{{ form.as_p }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info"
type="submit">Signup</button>
</div>
</form>
<div class="border-top pt-3">
<small class="text-muted">Aready have account <a
href="#" class="ml-2">SignIn</a></small>
</div>
</div>
{% endblock content %}
Main urls.py
from django.contrib import admin
from django.urls import path, include
from users import views as user_views
urlpatterns = [
path('admin/', admin.site.urls),
path('register/', user_views.register, name='register'),
path('blog/', include('blog.urls')),
]
Base.html inside of blog
<div class="col-md-8">
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{message.tags}}">
{{ message }}
</div>
{% endfor %}
{% endif %}
{% block content %}
{% endblock %}
</div>
The above one has only username and password, to add other attribute
- Create forms.py insides of users app
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username','email','password1','password2']
and change Views.py
from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import UserRegisterForm
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
messages.success(request,f"Account created for
{username}!")
return redirect('blog-home')
else:
form = UserRegisterForm()
return render(request, 'users/register.html', {'form':form})
12. Crispy form (to create awesome from in bootstrap)
- Install it
pip install django-crispy-forms
pip install crispy-bootstrap4
- Go to setting
'crispy_forms',
'crispy_bootstrap4',
CRISPY_TEMPLATE_PACK = 'bootstrap4'
- Load it above register.html
{% load crispy_forms_tags %}
{{ form|crispy }}
13. Login and Logout
- Import auth_views on urls.py
from django.contrib.auth import views as auth_views
path('login/',auth_views.LoginView.as_view(template_name='users/login.html'
), name='login'),
path('logout/',auth_views.LogoutView.as_view(template_name='users/
logout.html'), name='logout'),
- Create login.html inside users template
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4"> Login
</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info"
type="submit">Login</button>
</div>
</form>
<div class="border-top pt-3">
<small class="text-muted">Haven't an account ? <a
href="{% url 'register' %}" class="ml-2">Signup Here</a></small>
</div>
</div>
{% endblock content %}
- Add redirect at the end of setting.py
LOGIN_REDIRECT_URL = 'blog-home'
Logout.html
{% extends "blog/base.html" %}
{% block content %}
<h2>You have logged out</h2>
<div class="border-top pt-3">
<small class="text-muted">
<a href="{% url 'login' %}" class="ml-2">Sign in</a>
</small>
</div>
{% endblock content %}
Base.html
<div class="navbar-nav">
{% if user.is_authenticated %}
<a class="nav-item nav-link" href="{% url 'logout'
%}">Logout</a>
{% else %}
<a class="nav-item nav-link" href="{% url 'login'
%}">Login</a>
<a class="nav-item nav-link" href="{% url 'register'
%}">Register</a>
{% endif %}
</div>
- Add profile function inside of users views.py
def profile(request):
return render(request, 'users/profile.html')
profile.py inside template
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<h2>{{ user.username }}</h2>
{% endblock content %}
Urls.py
path('profile/', user_views.profile, name='profile'),
base.html
<div class="navbar-nav">
{% if user.is_authenticated %}
<a class="nav-item nav-link" href="{% url 'profile' %}">Profile</a>
<a class="nav-item nav-link" href="{% url 'logout' %}">Logout</a>
{% else %}
<a class="nav-item nav-link" href="{% url 'login' %}">Login</a>
<a class="nav-item nav-link" href="{% url 'register' %}">Register</a>
{% endif %}
</div>
- Login required pages
Views.py of users
from django.contrib.auth.decorators import login_required
@login_required
def profile(request):
return render(request, 'users/profile.html')
Setting.py
LOGIN_URL = 'login'
14. Profile
Models.py
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image =
models.ImageField(default='default.jpg',upload_to='profile_pics')
def __str__(self):
return f'{self.user.username} Profile'
To migrate Models
python manage.py makemigrations
python -m pip install Pillow
python manage.py makemigrations
python manage.py migrate
To compile locale
python manage.py makemessages
python manage.py complilemessages
admin.py inside users, to add Admin page
from django.contrib import admin
from .models import Profile
admin.site.register(Profile)
- Access Profile attribute on the views
python manage.py shell
>>> from django.contrib.auth.models import User
>>> User.objects.all()
>>> user = User.objects.filter(username='Habtamu').first()
>>> user.profile.image
profile_pics directory inside the project is created
- Change the path of media on setting.py, then I will store profile
pictures == media/profile_pics path
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # to access the media
from our pc on browser
MEDIA_URL = '/media/'
- To display profile info on the view
Profile.html
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<div class="media">
<img class="rounded-circle account-img"
src="{{ user.profile.image }}">
<div class="media-body">
<h2 class="account-heading">{{ user.username }}</h2>
<p class="text-secondary">{{ user.email }} </p>
</div>
</div>
</div>
{% endblock content %}
- To display profile image, we must fix on urls.py
from django.conf import settings
from django.conf.urls.static import static
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)
- Create signals.py file on users folder
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Profile
@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
apps.py on users folder
def ready(self):
import users.signals
15. Update User profile
- Inside forms.py
from .models import Profile
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email']
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['image']
Views.py
from .forms import UserRegisterForm, UserUpdateForm, ProfileUpdateForm
@login_required
def profile(request):
u_form = UserUpdateForm()
p_form = ProfileUpdateForm()
context = {
'u_form': u_form,
'p_form' : p_form
}
return render(request, 'users/profile.html' , context)
Profile.html
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<div class="media">
<img style="width:70px;height:70px;margin-right:7px"
class="rounded-circle account-img" src="{{ user.profile.image.url }}" />
<div class="media-body">
<h2 class="account-heading">{{ user.username }}</h2>
<p class="text-secondary">{{ user.email }} </p>
</div>
</div>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Profile
information</legend>
{{ u_form|crispy }}
{{ p_form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info"
type="submit">Update</button>
</div>
</form>
</div>
{% endblock content %}
On views.py
Add instance based on POST or not
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from .forms import UserRegisterForm, UserUpdateForm, ProfileUpdateForm
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
messages.success(request,f"{username} Your account are created
successfully, Login now !")
return redirect('login')
else:
form = UserRegisterForm()
return render(request, 'users/register.html', {'form':form})
@login_required
def profile(request):
if request.method == 'POST':
u_form = UserUpdateForm(request.POST, instance = request.user)
p_form = ProfileUpdateForm(request.POST, request.FILES, instance =
request.user.profile)
if u_form.is_valid() and p_form.is_valid():
u_form.save()
p_form.save()
messages.success(request, f"Your account has updated
successfully !")
return redirect('profile')
else:
u_form = UserUpdateForm(instance = request.user)
p_form = ProfileUpdateForm(instance = request.user.profile)
context = {
'u_form': u_form,
'p_form' : p_form
}
return render(request, 'users/profile.html', context)
- Resize image size
Models.py
from django.db import models
from django.contrib.auth.models import User
from PIL import Image
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image =
models.ImageField(default='default.jpg',upload_to='profile_pics')
def __str__(self):
return f'{self.user.username} Profile'
def save(self):
super().save()
img = Image.open(self.image.path)
if img.height > 300 or img.width > 300:
output_size = (300, 300)
img.thumbnail(output_size)
img.save(self.image.path)
- Add image on the home page of each cards
Index.html
<img style="width:80px;height:80px;margin-right:7px" class="rounded-circle
article-img" src="{{ post.author.profile.image.url }}"/>
16. CRUD
- Create Create, Display, Update and Delete functions on blog
views.py
from django.views.generic import ListView
Display
class PostListView(ListView):
model = Post
template_name='blog/index.html'
context_object_name = 'posts'
ordering = ['-posted_date'] # Display based on the date
urls.py on blog
from django.urls import path
from .views import PostListView
from . import views
urlpatterns = [
#path('',views.index, name='blog-home'),
path('',PostListView.as_view(), name='blog-home'),
path('about/',views.about, name='blog-about')
]
- To create Detail View
Urls.py
from django.views.generic import ListView, DetailView
path('post/<int:pk>/',PostDetailView.as_view(), name='post-detail'),
create post_detail.html on blog template
{% extends "blog/base.html" %}
{% block content %}
<div class="card" style="margin-top: 19px;">
<h5 class="card-header">
<div class="article-metadata">
<img style="width:80px;height:80px;margin-right:7px"
class="rounded-circle article-img"
src="{{ object.author.profile.image.url }}"/>
<a class="mr-2" href="#">{{ object.author }}</a>
<small class="text-muted">{{ object.posted_date|date:"F
d, Y" }}</small>
</div>
</h5>
<div class="card-body">
<h3><a class="article-title" href="#">{{ object.title }}</a>
</h3>
<p class="article-content">{{ object.content }}</p>
</div>
</div>
{% endblock content %}
- Go to Post detail page when we press one Post
Index.html
<h3><a class="article-title" href="{% url 'post-detail' post.id
%}">{{ post.title }}</a> </h3>
- Create New post on View (inside of blog app)
Views.py
from django.views.generic import ListView, DetailView, CreateView
class PostCreateView(CreateView):
model = Post
fields = ['title', 'content']
urls.py
from .views import PostListView, PostDetailView, PostCreateView
- Create post_form.html file inside blog template
Post_form.html
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">
Create Blog post
</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info"
type="submit">Post</button>
</div>
</form>
</div>
{% endblock content %}
- When we run, fill and submit the project, then NOT NULL constraint
failed:, so we must add on views.py
Views.py
class PostCreateView(CreateView):
model = Post
fields = ['title', 'content']
def form_valid(self,form):
form.instance.author = self.request.user
return super().form_valid(form)
models.py on blog
from django.urls import reverse
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
- Now it create new post and redirect to its own created post
- Another way to redirect post/new to login page if not logged
Views.py
from django.contrib.auth.mixins import LoginRequiredMixin # redirect to
login
class PostCreateView(LoginRequiredMixin, CreateView):
- Update
Views.py
from django.views.generic import ListView, DetailView, CreateView,
UpdateView
#Update
class PostUpdateView(LoginRequiredMixin, UpdateView):
model = Post
fields = ['title', 'content']
def form_valid(self,form):
form.instance.author = self.request.user
return super().form_valid(form)
Urls.py
from .views import PostListView, PostDetailView, PostCreateView,
PostUpdateView
path('post/<int:pk>/update',PostUpdateView.as_view(), name='post-update'),
- Delete a post
Views.py
from django.views.generic import ListView, DetailView, CreateView,
UpdateView, DeleteView
#Delete
class PostDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
model = Post
def test_func(self):
post = self.get_object()
if self.request.user == post.author:
return True
return False
Urls.py
from .views import PostListView, PostDetailView, PostCreateView,
PostUpdateView, PostDeleteView
path('post/<int:pk>/delete',PostDeleteView.as_view(), name='post-delete'),
- Confirm delete, Create delete_confirm.html
Post_delete_confirm.html
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">
Delete Post
</legend>
<h2>Are your sure to delete post "{{ object.title }}"? </h2>
</fieldset>
<div class="form-group">
<button class="btn btn-outline-danger"
type="submit">Delele</button>
<a class="btn btn-outline-secondary" href="{% url 'post-
detail' object.id %}">Cancel</a>
</div>
</form>
</div>
{% endblock content %}
- To get success_url
Views.py, inside of PostDeleteView function
success_url = '/blog/'
base.html
<a class="nav-item nav-link" href="{% url 'post-create' %}">New Post</a>
<a class="nav-item nav-link" href="{% url 'profile' %}">Profile</a>
<a class="nav-item nav-link" href="{% url 'logout' %}">Logout</a>
Post_detail.html
{% if object.author == user %}
<div>
<a class="btn btn-secondary btn-sm mt-1 mb-1" href="{% url 'post-
update' object.id %}"> Update </a>
<a class="btn btn-danger btn-sm mt-1 mb-1" href="{% url 'post-
delete' object.id %}"> Delete </a>
</div>
{% endif %}
17. Pagination
- Create posts.json file on and go to shell
>>> from django.core.paginator import Paginator
>>> posts = ['1','2','3','4','5']
>>> p = Paginator(posts,2)
>>> p.num_pages
>>> for page in p.page_range:
... print(page)
...
1
2
3
>>>
>>>
>>> p1= p.page(1)
>>> p1
>>> p1.number
>>> p1.object_list
>>> p1.has_previous()
>>> p1.has_next()
Views.py
Add on PostListView Function
paginate_by = 2
at the end of index.html on blog
{% endfor %}
{% if is_paginated %}
{% if page_obj.has_previous %}
<a class="btn btn-outline-info mb-4" href="?page=1">First</a>
<a class="btn btn-outline-info mb-4" href="?
page={{ page_obj.previous_page_number }}">Previous</a>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<a class="btn btn-info mb-4" href="?
page={{ num }}">{{ num }}</a>
{% elif num > page_obj.number|add:'-3' and num < page.obj.number|
add:'3' %}
<a class="btn btn-outline-info mb-4" href="?
page={{ num }}">{{ num }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a class="btn btn-outline-info mb-4" href="?
page={{ page_obj.next_page_number }}">Next</a>
<a class="btn btn-outline-info mb-4" href="?
page={{ page_obj.paginator.num_pages }}">Last</a>
{% endif %}
{% endif %}
Views.py for cruding users
from django.shortcuts import render, get_object_or_404
from django.contrib.auth.models import User
#Display Users
class UserPostListView(LoginRequiredMixin, ListView):
model = Post
template_name='blog/user_post.html'
context_object_name = 'posts'
ordering = ['-posted_date'] # Display based on the date
paginate_by = 2
def get_queryset(self):
user=get_object_or_404(User, username=self.kwargs.get('username'))
return Post.objects.filter(author=user).order_by('-posted_date')
Create user_post.html
{% extends "blog/base.html" %}
{% block content %}
<h2 class="mb-3">Posts by {{ view.kwargs.username }}
({{ page_obj.paginator.count }})</h2>
{% for post in posts %}
<div class="card" style="margin-top: 19px;">
<h5 class="card-header">
<div class="article-metadata">
<img style="width:80px;height:80px;margin-
right:7px" class="rounded-circle article-img"
src="{{ post.author.profile.image.url }}"/>
<a class="mr-2" href="{% url 'user-posts'
post.author.username %}">{{ post.author }}</a>
<small class="text-muted">{{ post.posted_date|
date:"F d, Y" }}</small>
</div>
</h5>
<div class="card-body">
<h3><a class="article-title" href="{% url 'post-detail'
post.id %}">{{ post.title }}</a> </h3>
<p class="article-content">{{ post.content }}</p>
</div>
</div>
{% endfor %}
{% if is_paginated %}
{% if page_obj.has_previous %}
<a class="btn btn-outline-info mb-4" href="?page=1">First</a>
<a class="btn btn-outline-info mb-4" href="?
page={{ page_obj.previous_page_number }}">Previous</a>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<a class="btn btn-info mb-4" href="?
page={{ num }}">{{ num }}</a>
{% elif num > page_obj.number|add:'-3' and num <
page.obj.number|add:'3' %}
<a class="btn btn-outline-info mb-4" href="?
page={{ num }}">{{ num }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a class="btn btn-outline-info mb-4" href="?
page={{ page_obj.next_page_number }}">Next</a>
<a class="btn btn-outline-info mb-4" href="?
page={{ page_obj.paginator.num_pages }}">Last</a>
{% endif %}
{% endif %}
{% endblock content %}
Index.html
<a class="mr-2" href="{% url 'user-posts' post.author.username
%}">{{ post.author }}</a>
Urls.py
from .views import PostListView, PostDetailView, PostCreateView,
PostUpdateView, PostDeleteView, UserPostListView
path('user/<username>',UserPostListView.as_view(), name='user-posts'),
18. Email and password reset
Go to project url
Urls.py
path('password-reset/',
auth_views.PasswordResetView.as_view(template_name='users/password_reset.ht
ml'), name='password_reset'),
create password_reset.html inside users app
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Reset Password</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Request
Password Reset</button>
</div>
</form>
</div>
{% endblock content %}
Password_reset_confirm.html
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Reset Password</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Reset
Password</button>
</div>
</form>
</div>
{% endblock content %}
Password_reset_done.html
{% extends "blog/base.html" %}
{% block content %}
<div class="alert alert-info">
An email has been sent with instructions to reset your password
</div>
{% endblock content %}
And on urls.py
path('password-reset/done/',
auth_views.PasswordResetDoneView.as_view(template_name='users/password_rese
t_done.html'),name='password_reset_done'),
Then, it needs confirm, so create password_reset_complete.html file
{% extends "blog/base.html" %}
{% block content %}
<div class="alert alert-info">
Your password has been set.
</div>
<a href="{% url 'login' %}">Sign In Here</a>
{% endblock content %}
Urls.py
path('password-reset/',
auth_views.PasswordResetView.as_view(
template_name='users/password_reset.html'
),
name='password_reset'),
path('password-reset/done/',
auth_views.PasswordResetDoneView.as_view(
template_name='users/password_reset_done.html'
),
name='password_reset_done'),
path('password-reset-confirm/<uidb64>/<token>/',
auth_views.PasswordResetConfirmView.as_view(
template_name='users/password_reset_confirm.html'
),
name='password_reset_confirm'),
path('password-reset-complete/',
auth_views.PasswordResetCompleteView.as_view(
template_name='users/password_reset_complete.html'
),
name='password_reset_complete'),
go to setting
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'mhlqxbcabxepcxht' # this password is generated on my
gmail
- There are some processes on gmail
Enhance safe browsing should on, must 2 step verification and app
password
19. Custom domain name for applicartion
- Find https://www.namecheap.com/ , but it is not free
20. Enable Https
- Go to https://letsencrypt.org/
21. Multi language in django
- Activate virtual
py -m venv venv
- Install django
pip install django
- Create app
python manage.py startapp setting
22. Model translation
pip install django-modeltranslation
setting.py
USE_L10N = True