Registration Setup
Create a new app User
-- to seperate the logic of registeration,login and logout and create a module that can be integrated in any Django application
In main app urls.py :
urlpatterns = [
path('users/', include('users.urls'))
]
in User urls.py :
from django.urls import path
from .import views
urlpatterns = [
path('sign_up/', views.index, name='users-sign-up')
]
Create forms.py in User app and write the following:
from django.contrib.auth.forms import UserCreationForm
from django import forms
from django.contrib.auth.models import User
class SignUpForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ['username','email','password1','password2']
def __init__(self, *args, **kwargs):
super(SignUpForm, self).__init__(*args, **kwargs)
for fieldname in ['password1','password2']:
self.fields[fieldname].help_text = None
In views (User) :
from django.shortcuts import render,redirect
from .forms import SignUpForm
def index(request):
if request.method == "POST":
form = SignUpForm(request.POST)
if form.is_valid():
form.save()
return redirect('login')
else:
form = SignUpForm()
context = {
'form':form
}
return render(request,'User/sign_up.html',context)
In Sign_up.html :
<title>{% block title %}Sign Up{% endblock %}</title>
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
<input type="submit" value="Register" class="btn btn-primary">
</form>
Add this to base.html to show title dynamically:
<title>{% block title %}{% endblock %}</title>
Login Setup
In the same urls.py:
from django.contrib.auth import views as auth_view
path('login/', auth_view.LoginView.as_view(template_name='User/login.html'), name='login'),
In Sign_in.html :
<title>{% block title %}Sign In{% endblock %}</title>
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
<input type="submit" value="Login" class="btn btn-primary">
</form>
In settings.py
LOGIN_REDIRECT_URL = 'home'
Optimize your navbar :
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
{% if request.user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{% url 'blog:create' %}">New BlogPost</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'logout' %}">Logout</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url 'login' %}">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'register' %}">Register</a>
</li>
{% endif %}
</ul>
</div>
Logout Setup
In the same urls.py:
path('logout/', views.LogoutView.as_view(next_page='home'), name='logout'),
In Logout.html : (only for the flow of execution)
<title>{% block title %}Logout{% endblock %}</title>
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
<input type="submit" value="Login" class="btn btn-primary">
</form>
<hr>
<div class="alert alert-info">
You have been logged out.
</div>
Use this url template tag wherever required in navbar:
{% url 'logout' %}
Profile Setup
In forms.py
from django.contrib.auth.forms import UserCreationForm
from django import forms
from django.contrib.auth.models import User
from .models import Profile
class SignUpForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ['username','email','password1','password2']
class EditProfile(forms.ModelForm):
class Meta:
model = User
fields = ['username','email']
def __init__(self, *args, **kwargs):
super(EditProfile, self).__init__(*args, **kwargs)
for fieldname in ['username', 'email']:
self.fields[fieldname].help_text = None
class EditPro(forms.ModelForm):
class Meta:
model = Profile
fields = ['bio','pic']
widgets = {
'bio': forms.Textarea(attrs={'class': 'form-control', 'rows': 5, 'placeholder': 'Write about yourself...'}),
'pic': forms.ClearableFileInput(attrs={'class': 'form-control'}),
}
def __init__(self, *args, **kwargs):
super(EditPro, self).__init__(*args, **kwargs)
for fieldname in ['bio', 'pic']:
self.fields[fieldname].help_text = None
In views.py
from django.shortcuts import render,redirect
from .forms import SignUpForm,EditProfile,EditPro
from django.contrib import messages
from django.contrib.auth.views import LogoutView
from myBlog.models import UserPost,Category
from django.contrib.auth.decorators import login_required
# Create your views here.
def index(request):
if request.method == "POST":
form = SignUpForm(request.POST)
if form.is_valid():
form.save()
return redirect('new_login')
else:
form = SignUpForm()
context = {
'form':form
}
return render(request,'User/sign_up.html',context)
@login_required
def userProfile(request):
if request.method == "POST":
u_form = EditProfile(request.POST or None,instance=request.user)
p_form = EditPro(request.POST or None,request.FILES or None,instance=request.user.profile)
if u_form.is_valid() and p_form.is_valid():
u_form.save()
p_form.save()
return redirect('profile')
else:
u_form = EditProfile(instance=request.user)
p_form = EditPro(instance=request.user.profile)
blog_count = UserPost.objects.filter(author=request.user).count()
category = Category.objects.filter(status = 0)
context = {
'u_form':u_form,
'p_form':p_form,
'blog_count':blog_count,
'category':category
}
return render(request,'User/profile.html',context)
*In urls.py *
path('profile/',views.profile, name='user-profile'),
In navbar.html
<a href="{% url 'user-profile' %}">Profile</a>
In User/profile.html
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block title %}Profile Page{% endblock %}
{% block content %}
<div class="container">
<div class="row mt-5 pt-3">
<div class="col-md-6 offset-md-3">
<div class="card my-3 shadow">
<div class="card-body">
<div class="row">
<!-- Profile Image -->
<div class="col-md-4 text-center">
{% if user.profile.pic %}
<img src="{{ user.profile.pic.url }}"
class="img-fluid rounded-circle mb-3 shadow-sm"
alt="{{ user.username }}">
{% else %}
<img src="https://via.placeholder.com/150"
class="img-fluid rounded-circle mb-3 shadow-sm"
alt="Default Profile">
{% endif %}
<h5 class="mt-2">{{ user.username }}</h5>
</div>
<!-- Profile Form -->
<div class="col-md-8">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<div class="d-grid">
<button type="submit" class="btn btn-primary">
Update Profile
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
Bootstrap Modal Example (optional)
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal">
Edit Profile
</button>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="modal-header">
<h1 class="modal-title fs-5" id="exampleModalLabel">Edit Profile</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-4 text-center">
<img src="{{ user.profile.pic.url }}" alt="Profile Picture" class="img-fluid rounded">
</div>
<div class="col-md-8">
{{ u_form|crispy }}
{{ p_form|crispy }}
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Save changes</button>
</div>
</form>
</div>
</div>
</div>
In User/models.py
from django.db import models
from django.contrib.auth.models import User
import os,datetime
from django.core.validators import FileExtensionValidator
class Profile(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
pic = models.ImageField(default='default.png',upload_to='avatars/',validators=[FileExtensionValidator(['png','jpg','jpeg','webp'])])
bio = models.TextField(blank=True,null=True)
def __str__(self):
return self.user.username
Serve Media Files
pip install pillow
# settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# 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)
Dump your all Static files for production
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / "staticfiles"
python manage.py collectstatic
admins.py
from django.contrib import admin
from .models import Profile
admin.site.register(Profile)
In template
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
Also Add default.jpg/png in media folder to show default pic
Use Django Signals to create profile automatically after user sign up
from .models import Profile
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save,sender = User)
def create_profile(sender,instance,created,*args, **kwargs):
if created:
Profile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
apps.py
from django.apps import AppConfig
class UserConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'user'
def ready(self):
import user.signals
That's it :) Happy Coding you all.
Top comments (0)