DEV Community

Cover image for Creating a follow and unfollow system in Django | python
vinayak
vinayak

Posted on • Updated on • Originally published at itsvinayak.hashnode.dev

Creating a follow and unfollow system in Django | python

Social Media giants like Instagram, Twitter, Facebook, and Github have one thing in common, that is it follow/unfollow feature. which allows the user to follow each other.

Here, in this post, we have tried to mimic this feature.
*Basic knowledge of Django is required

  1. Modules required :
    • Django :
pip install Django
Enter fullscreen mode Exit fullscreen mode
  1. Basic setup :

    • Command to make a project - here, the name of the project is named as "blog"
       django-admin startproject blog 
    
  • In blog folder create an app - here, the name of the app is named as "author"

       python manage.py startapp author
    
  1. code
    • After creating the author app, open the models.py file in the author
from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    following = models.ManyToManyField(
        "self", blank=True, related_name="followers", symmetrical=False
    )
    bio = models.TextField(max_length=200, blank=True, default="Bio")
    website = models.URLField(max_length=200, blank=True)


    def __str__(self):
          return f"{self.username} Profile"

Enter fullscreen mode Exit fullscreen mode

Here, the ManyToMany field will help us create a followings field as a user can follow many other users and many users can follow him.
Docs on ManyTOManyField

  • After creating models and running migrations, we need to work on views.py
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
from author.models import User


def profile(request, username):
    userProfile = User.objects.get(username=username)

    data = {
        "author": userProfile,
    }
    return render(request, "author/profile.html", data)


def followToggle(request, author):
    authorObj = User.objects.get(username=author)
    currentUserObj = User.objects.get(username=request.user.username)
    following = authorObj.following.all()

    if author != currentUserObj.username:
        if currentUserObj in following:
            authorObj.following.remove(currentUserObj.id)
        else:
            authorObj.following.add(currentUserObj.id)

    return HttpResponseRedirect(reverse(profile, args=[authorObj.username]))
Enter fullscreen mode Exit fullscreen mode

we have to functions here:

  1. profile() - this function handle user profile by accepting username as an argument

  2. followToggle() - this function handle follow/unfollow system for a user. This function takes a username as an argument, which our current user wants to follow/unfollow.

  • Now time to work on urls.py to connect views
from django.urls import path
from author import views

urlpatterns = [
    path("profile/<str:username>/", views.profile, name="profile"),
    path("followToggle/<str:author>/",views.followToggle, name="followToggle")
]
Enter fullscreen mode Exit fullscreen mode
  • Create a templates folder inside the templates folder, create an author/profile.html template.

*I have use bootstrap for my project. so, please ignore classes

{% extends "base.html" %}
{% load static %}
{% block header %}
{% endblock header %}

{% block content %}

<div class="pt-5 mt-5 pb-5 mb-5">
  <div class="container">
    <div class="main-body">
      <div class="row gutters-sm">
        <div class="col-md-4 mb-3">
          <div class="card">
            <div class="card-body">
              <div class="d-flex flex-column align-items-center text-center">
                <img src="{{ author.image.url }}" alt="{{ author.username }}" class="rounded-circle" width="150" />
                <div class="mt-3">
                  <h4>{{ author.username }}</h4>
                  <div class="row">
                    <b> following : </b>
                    <p class="text-muted"> {{ author.following.count }} </p>
                    &nbsp;&nbsp;&nbsp;&nbsp;
                    <b> followers : </b>
                    <p class="text-muted"> {{ author.followers.count }} </p>
                  </div>
                  <h6 class="text-muted font-size-sm">
                    {{ author.bio }}
                  </h6>
                  {% if user.is_authenticated %}
                    {% if user in author.following.all %}
                        <a href="{% url 'followToggle' author=author.username  %}" class="btn btn-primary">Unfollow</a>
                      {% else %}
                        <a  href="{% url 'followToggle' author=author.username  %}" class="btn btn-primary"> Follow </a>
                    {% endif %}
                      <button class="btn btn-outline-primary">Message</button>
                  {% else %}
                    <p class="text-muted"> please, login to follow </p>
                  {% endif %}
                </div>
              </div>
            </div>
          </div>

          <div class="card mt-3">
            <ul class="list-group list-group-flush">
              {% if author.website %}
              <li class="list-group-item d-flex justify-content-between align-items-center flex-wrap">
                <h6 class="mb-0">
                  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
                    stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
                    class="feather feather-globe mr-2 icon-inline">
                    <circle cx="12" cy="12" r="10"></circle>
                    <line x1="2" y1="12" x2="22" y2="12"></line>
                    <path
                      d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z">
                    </path>
                  </svg>Website
                </h6>
                <span class="text-secondary">{{ author.website }}</span>
              </li>
              {% endif %}
            </div>

          </div>
        </div>
      </div>
    </div>
</div>


{% endblock content %}
Enter fullscreen mode Exit fullscreen mode

this is the profile page for the author we want to follow/unfollow, we get this page by passing "username" to profile views

here,

  • {{ author.following.count }} : this tag represents the count of users following the current user
  • {{ author.followers.count }}: this tag represents the count of users followed by the current user, this type of relationship tag is called reverse or backward relationship docs

To follow/unfollow this user we are using {% url 'followToggle' author=author.username %} this URL tag. follow and unfollow text on the button is represented by looking if the user exits in the author following list

That's it. hope, you like it.

Top comments (3)

Collapse
 
ericchapman profile image
Eric The Coder • Edited

Hi, good post. One tips. When you create your post with dev.to editor use the word python just after you begin a code section (just after the triple tick). example of the result:

# no python keyword
name = 'Mike'
Enter fullscreen mode Exit fullscreen mode
# with python keyword
name =  'Mike'
Enter fullscreen mode Exit fullscreen mode

By using the python keyword. Your code will be syntax colored and then easier to read.

Collapse
 
itsvinayak profile image
vinayak

Thanks for the advice

Collapse
 
alimobasheri profile image
MirAli Mobasheri

Great post! Actually I think we need more practical tutorials of Django on dev. Thanks👍