Building a Social Media Site With Python and Django: Part 10 Final Improvements Part 2

Video Tutorial

Code on Github

In this tutorial, we are going to finish up making some small final improvements to the application. This time, we are going to add a way to view a list of followers, we will improve the profile styles, and we will fix an issue with the navbar profile link. Let’s start with adding a followers list.

Adding a List of Followers

First we need to create a new view to get all of the followers. This will be very similar to other views that we have created. We will use the generic view class and get the profile from the url and then get all of the followers from that profile. We can then add a url path for this view and then create a template to list out all of the followers.

class ListFollowers(View):
def get(self, request, pk, *args, **kwargs):
profile = UserProfile.objects.get(pk=pk)
followers = profile.followers.all()
context = {
'profile': profile,
'followers': followers,
}
return render(request, 'social/followers_list.html', context)
path('profile/<int:pk>/followers', ListFollowers.as_view(), name='followers-list'),
{% extends 'landing/base.html' %}{% block content %}
<div class="container">
<div class="row mt-5">
<div class="col-md-3 col-sm-6">
<a href="{% url 'profile' profile.pk %}" class="btn btn-light">Back to Profile</a>
</div>
</div>
<div class="row justify-content-center mt-3">
<div class="col-md-5 col-sm-12">
{% if profile.name %}
<h3>Followers for {{ profile.name }}</h5>
{% else %}
<h3>Followers for @{{ profile.user.username }}</h5>
{% endif %}
</div>
</div>
{% for follower in followers %}
<div class="row justify-content-center">
<div class="col-md-5 col-sm-12 position-relative my-3">
<a href="{% url 'profile' follower.profile.pk %}"><img class="rounded-circle post-img" height="60" width="60" src="{{ follower.profile.picture.url }}" /></a>
<a href="{% url 'profile' follower.profile.pk %}" class="post-link"><h5 class="mt-3">@{{ follower.username }}</h5></a>
</div>
</div>
{% endfor %}
</div>
{% endblock content %}

You could change this tempate to list them out in multiple rows, but for this example we will just keep it all in one row. Now let’s update the profile to make it look a little better than it does currently.

Improve Profile Styles

We will center the image and name, and we will move the other info except the bio to its own card. Let’s also change the post list width to match the rest of the profile.

{% extends 'landing/base.html' %}{% block content %}
<div class="container">
<div class="row mt-5">
<div class="col-md-3 col-sm-6">
<a href="{% url 'post-list' %}" class="btn btn-light">Back to Feed</a>
</div>
</div>
<div class="row justify-content-center mt-5">
<div class="card col-md-8 col-sm-12 shadow-sm px-5 pt-3">
<div class="text-center">
<img src="{{ profile.picture.url }}" class="rounded-circle" width="100" height="100" />
{% if profile.name %}
<h3 class="py-4">{{ profile.name }}
<span>
{% if request.user == user %}
<a href="{% url 'profile-edit' profile.pk %}" class="edit-color"><i class="far fa-edit"></i></a>
{% endif %}
</span></h3>
{% endif %}
</div>

<div class="mb-3">
{% if profile.bio %}
<p>{{ profile.bio }}</p>
{% endif %}
<a href="{% url 'followers-list' profile.pk%}" class="post-link">Followers: {{ number_of_followers }}</a>
</div>
</div>
</div>
<div class="row justify-content-center mt-5">
<div class="card col-md-8 col-sm-12 shadow-sm px-5 pt-3">
<div>
{% if profile.location %}
<p>Location: {{ profile.location }}</p>
{% endif %}
{% if profile.birth_date %}
<p>Birthday: {{ profile.birth_date }}</p>
{% endif %}
</div>

<div class="mb-3">
{% if user == request.user %}
{% else %}
{% if is_following %}

<form method="POST" action="{% url 'remove-follower' profile.pk %}">
{% csrf_token %}
<button class="btn btn-outline-danger" type="submit">UnFollow</button>
</form>
{% else %}
<form method="POST" action="{% url 'add-follower' profile.pk %}">
{% csrf_token %}
<button class="btn btn-outline-success" type="submit">Follow</button>
</form>
{% endif %}
{% endif %}
</div>
</div>
</div>
{% for post in posts %}
<div class="row justify-content-center mt-5">
<div class="col-md-8 col-sm-12 border-bottom position-relative">
<div>
<a href="{% url 'profile' post.author.profile.pk %}"><img class="rounded-circle post-img" height="30" width="30" src="{{ post.author.profile.picture.url }}" /></a>
<p class="post-text"><a class="text-primary post-link" href="{% url 'profile' post.author.profile.pk %}">@{{ post.author }}</a> {{ post.created_on }}</p>
</div>
<div class="position-relative">
<p>{{ post.body }}</p>
<a class="stretched-link" href="{% url 'post-detail' post.pk %}"></a>
</div>
<div class="d-flex flex-row">
<form method="POST" action="{% url 'like' post.pk %}">
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}">
<button class="remove-default-btn" type="submit"><i class="far fa-thumbs-up"></i> <span>{{ post.likes.all.count }}</span></button>
</form>
<form method="POST" action="{% url 'dislike' post.pk %}">
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}">
<button class="remove-default-btn" type="submit"><i class="far fa-thumbs-down"></i> <span>{{ post.dislikes.all.count }}</span></button>
</form>
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock content %}

Fix Navbar Profile Link

Finally, let’s fix the profile link. If you go to a different profile it will just link you back to the user’s profile that you are currently on and not the logged in user’s profile. There was just a small typo with how we did it previously, so let’s change user.profile.pk to request.user.profile.pk in our dropdown menu in the navbar.

<li><a class="dropdown-item" href="{% url 'profile' request.user.profile.pk %}">Profile</a></li>

This will probably complete this series. At this point, we have a functional social media application! There’s plenty of ways to improve off of this from this point, which would be a great exercise if you wanted to take it further from this point.