During Registration, only basic User information is stored. Now we will allow users to update their Profile Photo, Mobile Number and Bio.
from django import forms
from .models import UserProfile
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = [
"ProfilePhoto",
"Mobile",
"Bio"
]
from django.contrib.auth.decorators import login_required
from .forms import UserProfileForm
@login_required
def profile(request):
profile = request.user.userprofile
if request.method == "POST":
form = UserProfileForm(
request.POST,
request.FILES,
instance=profile
)
if form.is_valid():
form.save()
else:
form = UserProfileForm(
instance=profile
)
return render(
request,
"profile.html",
{
"form": form
}
)
The instance parameter tells Django to update an existing record instead of creating a new one.
UserProfileForm(
instance=profile
)
Without the instance parameter, Django would create a new record instead of updating the existing UserProfile.
Since the Profile contains an ImageField, we must allow users to upload image files.
{% extends 'base.html' %}
{% block content %}
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card shadow">
<div class="card-header">
<h3>My Profile</h3>
</div>
<div class="card-body">
<form method="POST"
enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-primary">
Save Profile
</button>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
path(
"profile/",
views.profile,
name="profile"
),
| Concept | Purpose |
|---|---|
| request.FILES | Receives uploaded image files. |
| multipart/form-data | Required for uploading files using HTML forms. |
| ModelForm | Creates a form directly from a Django Model. |
| ImageField | Stores uploaded Profile Photos. |
After uploading a Profile Photo, we can display it in the Navigation Bar along with the logged-in Username.
If the user has not uploaded a Profile Photo, a default User icon will be displayed.
{% if user.is_authenticated %}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle"
href="#"
role="button"
data-bs-toggle="dropdown">
{% if user.userprofile.ProfilePhoto %}
<img src="{{ user.userprofile.ProfilePhoto.url }}"
width="35"
height="35"
class="rounded-circle me-2">
{% else %}
<i class="fa-solid fa-user"></i>
{% endif %}
{{ user.username }}
</a>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item"
href="{% url 'profile' %}">
My Profile
</a>
</li>
<li>
<a class="dropdown-item"
href="{% url 'logout' %}">
Logout
</a>
</li>
</ul>
</li>
{% endif %}
| Code | Purpose |
|---|---|
| user.userprofile | Accesses the UserProfile linked to the logged-in User. |
| ProfilePhoto.url | Returns the URL of the uploaded Profile Photo. |
| {% if %} | Checks whether the Profile Photo exists. |
| rounded-circle | Displays the image as a circular profile picture. |
Some pages should only be accessible to authenticated users.
Django provides the @login_required decorator to restrict access to specific Views.
from django.contrib.auth.decorators import login_required
@login_required
def profile(request):
profile = request.user.userprofile
...
return render(
request,
"profile.html",
{
"form": form
}
)
Open settings.py and add:
LOGIN_URL = "login"
The @login_required decorator checks whether the current user is authenticated before executing the View.
User Requests Profile Page
│
▼
Is User Logged In?
│ │
Yes No
│ │
▼ ▼
Open Page Redirect to Login
This helps protect sensitive pages from unauthorized access.
A Comment allows registered users to share their thoughts about a Blog Post.
Each Comment belongs to one Blog Post and is submitted by one User.
from django.contrib.auth.models import User
class Comment(models.Model):
Post = models.ForeignKey(
Post,
on_delete=models.CASCADE
)
User = models.ForeignKey(
User,
on_delete=models.CASCADE
)
Comment = models.TextField()
CreatedOn = models.DateTimeField(
auto_now_add=True
)
class Meta:
db_table = "Comments"
def __str__(self):
return self.User.username
python manage.py makemigrations
python manage.py migrate
from django import forms
from .models import Comment
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = [
"Comment"
]
Logged-in users can submit Comments from the Blog Details page.
from .forms import CommentForm
@login_required
def blogDetails(request, slug):
post = get_object_or_404(
Post,
Slug=slug,
IsPublished=True
)
comments = Comment.objects.filter(
Post=post
).order_by("-CreatedOn")
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.Post = post
comment.User = request.user
comment.save()
return redirect(
"blogdetails",
slug=post.Slug
)
else:
form = CommentForm()
return render(
request,
"blogdetails.html",
{
"post": post,
"form": form,
"comments": comments
}
)
<hr>
<h3>Comments</h3>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-primary">
Post Comment
</button>
</form>
<hr>
{% for comment in comments %}
<div class="card mb-3">
<div class="card-body">
<strong>
{{ comment.User.username }}
</strong>
<small class="text-muted">
{{ comment.CreatedOn }}
</small>
<p class="mt-2 mb-0">
{{ comment.Comment }}
</p>
</div>
</div>
{% empty %}
<p>
No comments yet.
</p>
{% endfor %}
| Concept | Purpose |
|---|---|
| commit=False | Creates the Comment object without saving it immediately. |
| comment.Post = post | Associates the Comment with the current Blog Post. |
| comment.User = request.user | Stores the logged-in User as the author of the Comment. |
| redirect() | Refreshes the page after saving the Comment. |
✓ Edit User Profile
✓ Upload Profile Photo
✓ Display Profile Photo in Navbar
✓ @login_required
✓ Comment Model
✓ Display Comments
✓ commit=False
✓ request.user
Implement today's User Profile and Comment features in your News Portal.