Djitter - how to build a twitter clone using Django 2.0 - Part eight

Djitter - how to build a twitter clone using Django 2.0 - Part eight

Published 16. jun 2018 12:13 by Stein Ove Helset

A social media needs functionality for following users. And that is exactly what we're going to create now.

The last thing we need to think about it this tutorial before we have an actual working clone is that we need to make it possible to follow and unfollow users. In this part we'll make it possible to follow/unfollow and also see which djeeters a djeeter follows.

Let's create a new file which can be used both for listing out followers but also users you are following. Once it's created you can open it in your editor.


$ touch templates/users.html

Write the following code inside the file.


{% extends 'base.html' %}

{% block main %}
<div>
  <h1>{{ title }}</h1>
  <ul>
    {% for djeeter in djeeterprofiles %}
      <li><a href="/{{ djeeter.user.username }}/">@{{ djeeter.user.username }}</a></li>
    {% endfor %}
  </ul>
</div>
{% endblock %}

We need to change the djeeterprofile/views.py file and add two more views at the bottom. Open it in your editor and add the following views.


def follows(request, username):
  user = User.objects.get(username=username)
  djeeterprofiles = user.djeeterprofile.follows
    
  return render(request, 'users.html', {'title': 'Follows', 'djeeterprofiles': djeeterprofiles})
  
def followers(request, username):
  user = User.objects.get(username=username)
  djeeterprofiles = user.djeeterprofile.followed_by
    
  return render(request, 'users.html', {'title': 'Followers', 'djeeterprofiles': djeeterprofiles})

We need to change to djitter/urls.py so open that one and change it like this.


from django.urls import path

from djeet.views import feed
from djeeterprofile.views import frontpage, signout, profile, follows, following # Change this, add ", follows, following"

urlpatterns = [
  path('', frontpage, name='frontpage'),
  path('feed/', feed, name='feed'),
  path('signout/', signout, name='signout'),
  path('<str:username>/follows/', follows, name='follows'), # Add this line
  path('<str:username>/following/', following, name='following'),  # Add this line
  path('<str:username>/', profile, name='profile'),
]

Next we can add links from the profile page to the followers/following pages. Open profile.html and make the following changes.


{% extends 'templates/base.html' %}

{% block main %}
<div class="row">
  <!-- Feed -->
  <div class="col-9">
    <h3>@{{ user.username }}</h3>

    <hr> # Add this line

    <b><a href="/{{ user.username }}/follows/">Follows:</a></b> {{ user.djeeterprofile.follows.count }} -  # Add this line<
    <b><a href="/{{ user.username }}/followers/">Followers:</a></b> {{ user.djeeterprofile.followed_by.count }}  # Add this line

    {% ifnotequal request.user user %}# Add this line
      <hr> # Add this line

      {% if request.user.djeeterprofile in user.djeeterprofile.followed_by.all %} # Add this line
        <a href="/{{ user.username }}/stopfollow/" class="btn btn-danger">Stop follow</a> # Add this line
      {% else %} # Add this line
        <a href="/{{ user.username }}/follow/" class="btn btn-success">Follow</a> # Add this line
      {% endif %} # Add this line
    {% endifnotequal %}# Add this line

    <hr> # Add this line

    {% if user.djeets.all %}
      {% for djeet in user.djeets.all %}
        <div class="card" style="margin-bottom: 20px;">
          <div class="card-body">
            <h5 class="card-title">@{{ djeet.user.username }}</h5>
            <p class="card-text"><b>{{ djeet.created_at }}</b> - {{ djeet.body }}</p>
          </div>
        </div>
      {% endfor %}
    {% else %}
      <p>No djeets yet!</p>
    {% endif %}
  </div>

  <!-- Sidebar -->
  <div class="col-3">
    <h3>Add djeet</h3>

    {% if form.errors %}
      {% for field in form %}
        {% for error in form.errors %}
          <div class="alert alert-danger">
            <b>{{ error|escape }}</b>
          </div>
        {% endfor %}
      {% endfor %}
      {% for error in form.non_field_errors %}
        <div class="alert alert-danger">
          <b>{{ error|escape }}</b>
        </div>
      {% endfor %}
    {% endif %}

    <form action="." method="post">
      {% csrf_token %}

      {% for field in form %}
        <div class="form-group">
          {{ field }}
        </div>
      {% endfor %}

      <input type="hidden" value="{{ request.path }}" name="redirect">
      <input type="submit" value="Post djeet" class="btn btn-primary">
    </form>
  </div>
</div>
{% endblock %}

We have added a couple of new lines were we print the number of followers and the number of djeeters the users is following. We also added a new button for following and stop following a djeeter.

Make the following changes to the djeeterprofile/views.py.


from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect

@login_required
def follow(request, username):
  user = User.objects.get(username=username)
  request.user.djeeterprofile.follows.add(user.djeeterprofile)
  
  return redirect('/' + user.username + '/')

@login_required
def stopfollow(request, username):
  user = User.objects.get(username=username)
  request.user.djeeterprofile.follows.delete(user.djeeterprofile)
  
  return redirect('/' + user.username + '/')

These two new functions are very similar. One of them starts following a djeeter and the other stops following a djeeter. First we get the user from the database and then we add or remove that user from the authenticated user (request.user).


from django.urls import path

from djeet.views import feed
from djeeterprofile.views import frontpage, signout, profile, follows, followers, follow, stopfollow # Change this, add ", follow, stopfollow"

urlpatterns = [
  path('', frontpage, name='frontpage'),
  path('feed/', feed, name='feed'),
  path('signout/', signout, name='signout'),
  path('<str:username>/follows/', follows, name='follows'),
  path('<str:username>/followers/', followers, name='followers'),
  path('<str:username>/follow/', follow, name='follow'), # Add this line
  path('<str:username>/stopfollow/', stopfollow, name='stopfollow'), # Add this line
  path('<str:username>/', profile, name='profile'),
]

Here we just import the two new views for following and unfollowing a djeeter, and the two new views for showing who a djeeter is following and is followed by. Last but not least we add the four new paths to the urlpatterns array so Django will be aware of the views.

If you've got any questions your are more than welcome to leave a comment and I'll answer as soon as possible.

Next part

Share this post

Comments

martin

25. sep 2018 15:06

hei! just a heads-up: seems that in the first code block the closing </div> tag is missing before {% endblock %}

p.s.: I don't mind if you delete these notes after fixing it, if you get around doing the fix. I'm just noting what I find since it's a beginner tutorial and someone might get confused if there's a missing piece.

Stein Ove Helset

26. sep 2018 05:42

Hi Martin! Added the closing div.
Thanks for pointing out these different typos!
I'll let your comments stay since they might help other who have taken the tutorial before the typos got fixed!

Add comment