DEV Community

Cover image for Build a Social Media Website with Django — Part 3 (Users App Templates)
Kumar Shubham
Kumar Shubham

Posted on • Originally published at towardsdatascience.com

Build a Social Media Website with Django — Part 3 (Users App Templates)

So, in the second part, we defined all the backend part of the Users App, like we defined all the URLs, views, models, forms and registered our models with the admin panel.

So, now in the third part, we will focus on all the templates for displaying the logic we wrote in the Users app. As you already know, Users app deals with all the authentication, profile, friends, search users, find new friends and such other things.

So, in this part, there would be lots of HTML since we are dealing with the part of the templates. It will take in the data passed by the views.py file of Users app and will help display the data to the user and take user input via forms.

So, we put all our templates in the following location: templates/users inside of the users’ folder. It is the Django’s naming convention to put data there as Django looks for templates in that location.

We will deal with templates one by one. There are 12 of them. We won’t go into detail much as its mostly HTML and CSS classes and we would talk only about the logic part which we use in templates to define who has access to what. So, let’s begin:

login.html

Let’s start with the login part. This template will let users sign in into our website. This displays the Login Form and we are using the crispy forms to stylize our forms using Bootstrap4. In Django, forms are very easy to render.

We have a submit button and forgot password option, Also, we have a link to the registration page.

We are extending the layout template from our Feeds app. Each template extends the layout which contains the header and footer part. Don’t worry for now about the layout.html file since we would cover it in Part 5 of the tutorial series.

{% extends "feed/layout.html" %} {% load static %} {% load crispy_forms_tags %}
{% block cssfiles %} {% endblock cssfiles %} {% block content %}
<br />
<div class="container">
  <div class="row">
    <div class="col-sm-9 col-md-7 col-lg-5 mx-auto">
      <div class="card card-signin my-5">
        <div class="card-body">
          <h5 class="card-title text-center"><b>Sign In</b></h5>
          <form class="form-signin" method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
              <br />
              {{ form|crispy }}
            </fieldset>
            <div class="form-group">
              <button
                class="btn btn-lg btn-primary btn-block text-uppercase"
                type="submit"
              >
                Login</button
              ><br /><br />
              <a
                class="btn btn-lg btn-warning btn-block text-uppercase"
                href="{% url 'password_reset' %}"
                >Forgot Password?</a
              >
            </div>
            <small
              ><p class="text-center">
                Not registered yet!
                <a href="{% url 'register' %}"><b>Register Now!</b></a>
              </p></small
            >
          </form>
        </div>
      </div>
    </div>
  </div>
</div>
{% endblock content %}
Enter fullscreen mode Exit fullscreen mode

register.html

Next, we move to the registration page for our website. This page will let users sign up into our website. It also displays the form and then the submit button. We have a link to the login page for the existing users.

{% extends "feed/layout.html" %} {% load crispy_forms_tags %} {% load static %}
{% block content %}
<br />
<div class="container">
  <div class="row">
    <div class="col-sm-9 col-md-9 col-lg-7 mx-auto">
      <div class="card card-signin my-5">
        <div class="card-body">
          <h5 class="card-title text-center"><b>Register</b></h5>
          <form class="form-signin" method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
              <br />
              {{ form|crispy }}
            </fieldset>
            <div class="form-group">
              <button
                class="btn btn-lg btn-primary btn-block text-uppercase"
                type="submit"
              >
                Sign Up</button
              ><br /><br />
            </div>
            <small
              ><p class="text-center">
                Already Registered!
                <a href="{% url 'login' %}"><b>Login Now!</b></a>
              </p></small
            >
          </form>
        </div>
      </div>
    </div>
  </div>
</div>
{% endblock content %}
Enter fullscreen mode Exit fullscreen mode

logout.html

Next, we have the Logout page. It just displays a message telling the users that they have been logged out of the website. They are given an option to log in again.

{% extends "feed/layout.html" %} {% load static %}
{% block content %} <br /><br />
<div class="container">
  <div class="row">
    <div class="col-sm-9 col-md-7 col-lg-5 mx-auto">
      <div class="card card-signin my-5">
        <div class="card-body">
          <h5 class="card-title text-center">
            <b>You have been logged out!</b>
          </h5>
          <form class="form-signin">
            <div class="form-group">
              <a
                class="btn btn-lg btn-info btn-block text-uppercase"
                href="{% url 'login' %}"
                >Login Again</a
              >
            </div>
          </form>
        </div>
      </div>
    </div>
  </div>
</div>
{% endblock content %}
Enter fullscreen mode Exit fullscreen mode

request_password_reset.html

This is the form to let user request password reset. User should submit their email address and click on the reset button. Then they would be sent a link to their email address.

{% extends "feed/layout.html" %} {% load static %} {% load crispy_forms_tags %}
{% block content %}
<br />
<div class="container">
  <div class="row">
    <div class="col-sm-9 col-md-7 col-lg-5 mx-auto">
      <div class="card card-signin my-5">
        <div class="card-body">
          <h5 class="card-title text-center"><b>Reset Password</b></h5>
          <form class="form-signin" method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
              <br />
              {{ form|crispy }}
            </fieldset>
            <div class="form-group">
              <button
                class="btn btn-lg btn-primary btn-block text-uppercase"
                type="submit"
              >
                Request Password Reset</button
              ><br />
            </div>
          </form>
        </div>
      </div>
    </div>
  </div>
</div>
{% endblock content %} 
Enter fullscreen mode Exit fullscreen mode

password_reset_done.html

This page displays the message that the reset link has been sent to their email address. We also give a button which opens up the Gmail for the user.

{% extends "feed/layout.html" %} {% load static %}
{% block content %}
<br />
<div class="container">
  <div class="row">
    <div class="col-sm-9 col-md-7 col-lg-5 mx-auto">
      <div class="card card-signin my-5">
        <div class="card-body">
          <h5 class="card-title text-center">
            <b
              >An email has been sent with instructions to reset your
              password.</b
            >
          </h5>
          <form class="form-signin">
            <div class="form-group">
              <a
                class="btn btn-lg btn-warning btn-block text-uppercase"
                href="https://mail.google.com/mail/u/0/"
                >Open Gmail</a
              >
            </div>
          </form>
        </div>
      </div>
    </div>
  </div>
</div>
{% endblock content %} 
Enter fullscreen mode Exit fullscreen mode

password_reset_confirm.html

This page opens up when you click on the reset link which has been sent to you. You can make a new password here and then click on the button to change the password.

{% extends "feed/layout.html" %} {% load crispy_forms_tags %} {% load static %}
{% block cssfiles %} {% endblock cssfiles %} {% block content %}
<br />

<div class="container">
  <div class="row">
    <div class="col-sm-9 col-md-7 col-lg-5 mx-auto">
      <div class="card card-signin my-5">
        <div class="card-body">
          <h5 class="card-title text-center"><b>Reset Password</b></h5>
          <form class="form-signin" method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
              <br />
              {{ form|crispy }}
            </fieldset>
            <div class="form-group">
              <button
                class="btn btn-lg btn-primary btn-block text-uppercase"
                type="submit"
              >
                Reset Password</button
              ><br />
            </div>
          </form>
        </div>
      </div>
    </div>
  </div>
</div>
{% endblock content %} {% block jsfiles %}{% endblock jsfiles %}
Enter fullscreen mode Exit fullscreen mode

password_reset_complete.html

This page just shows that the user’s password has been reset and can log in using his new credentials now.

{% extends "feed/layout.html" %} {% load static %}
{% block content %}

<div class="container">
  <div class="row">
    <div class="col-sm-9 col-md-7 col-lg-5 mx-auto">
      <div class="card card-signin my-5">
        <div class="card-body">
          <h5 class="card-title text-center">
            <b>Your new password has been set.</b>
          </h5>
          <form class="form-signin">
            <div class="form-group">
              <a
                class="btn btn-lg btn-info btn-block text-uppercase"
                href="{% url 'login' %}"
                >Sign In Here</a
              >
            </div>
          </form>
        </div>
      </div>
    </div>
  </div>
</div>

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

profile.html

This is probably the most complicated one which has lots of stuff going in. First, we can see the {% block searchform %} which has a search bar to search for users. It is displayed in the navbar of the website and is not a part of the profile.html. It is just extending the navbar part so that the search form does not display on each page.

Now, coming to the profile part, we can search first we have a card which displays our profile details such as profile pic, the number of friends and number of posts shared.

Now we have placed a restriction for only the user whose profile we are looking at can view the friends' list and not anyone else. The posts shared can be seen by anyone. So, we have put a check there ({% if request.user == u%}) which checks for is current user equal to the user whose profile is being viewed.

Now, next, we have an option of Edit Profile if the current user is the user whose profile is being viewed. This restricts anyone else to update our profile.

We also have various options such as Add Friend, Cancel Request, Reject Request, Accept Request, Unfriend depending on the conditions.

  1. Add Friend — If a user is not our friend, we can send him a friend request.
  2. Cancel Request — If we have already sent a request to the user, we can cancel it.
  3. Accept Request — If that user has sent us a friend request, we can accept it.
  4. Reject Request — If that user has sent us a friend request, we can also reject it.
  5. Unfriend — If the user is already our friend and we want to remove him from our friends, we can unfriend him.

If the current user is the user whose profile is being viewed, then we get two lists below.

  1. Sent friend requests — It contains all the users whom we have sent a request. We can cancel the request from there.
  2. Received friend requests — It contains all the requests we have received. We can accept or reject them.
{% extends "feed/layout.html" %} {% load static %} {% block cssfiles %} {%
endblock cssfiles %} {% block searchform %}
<form
  class="form-inline my-2 my-lg-0 ml-5"
  action="{% url 'search_users' %}"
  method="get"
>
  <input name="q" type="text" placeholder="Search users.." />
  <button class="btn btn-success my-2 my-sm-0 ml-4" type="submit">
    Search
  </button>
</form>
{% endblock searchform %} {% block content %}

<div class="main-content">
  <div class="container mt-7">
    <div class="row">
      <div class="col-xl-8 m-auto order-xl-2 mb-5 mb-xl-0">
        <div class="card card-profile shadow">
          <div class="row justify-content-center">
            <div class="col-lg-3 order-lg-2">
              <div class="card-profile-image">
                <a href="{{ u.profile.image.url }}">
                  <img
                    src="{{ u.profile.image.url }}"
                    class="rounded-circle"
                    width="160px"
                    height="160px"
                  />
                </a>
              </div>
            </div>
          </div>
          <div
            class="card-header text-center border-0 pt-8 pt-md-4 pb-0 pb-md-4"
          ></div>
          <div class="card-body pt-0 pt-md-4">
            <div class="row">
              <div class="col">
                <div
                  class="card-profile-stats d-flex justify-content-center mt-md-5"
                >
                  <div>
                    <span class="heading">{{ u.profile.friends.count }}</span>
                    {% if request.user == u %}
                    <span class="description"
                      ><a href="{% url 'friend_list' %}">Friends</a></span
                    >
                    {% else %}
                    <span class="description">Friends</span>
                    {% endif %}
                    <span class="heading">{{ post_count }}</span>
                    <span class="description"
                      ><a href="{% url 'user-posts' u.username %}"
                        >Posts</a
                      ></span
                    >
                  </div>
                </div>
              </div>
            </div>
            <div class="text-center">
              <h3>{{ u }}</h3>
              <p>{{ u.profile.bio }}</p>
              <hr class="my-2" />
              {% if request.user == u %}
              <a class="btn btn-info" href="{% url 'edit_profile' %}"
                >Edit Profile</a
              >
              {% else %} {% if button_status == 'not_friend' %}
              <small
                ><a
                  class="btn btn-primary"
                  href="/users/friend-request/send/{{ u.id }}"
                  >Add Friend</a
                ></small
              >
              {% elif button_status == 'friend_request_sent' %}
              <small
                ><a
                  class="btn btn-warning"
                  href="/users/friend-request/cancel/{{ u.id }}"
                  >Cancel Request</a
                ></small
              >
              {% elif button_status == 'friend_request_received' %}
              <small
                ><a
                  class="btn btn-success mr-2"
                  href="/users/friend-request/accept/{{ u.id }}"
                  >Accept Request</a
                ></small
              >
              <small
                ><a
                  class="btn btn-danger"
                  href="/users/friend-request/delete/{{ u.id }}"
                  >Reject Request</a
                ></small
              >
              {% else %}
              <small
                ><a
                  class="btn btn-danger"
                  href="/users/friend/delete/{{ u.id }}"
                  >UnFriend</a
                ></small
              >
              {% endif %} {% endif %}
            </div>
          </div>
        </div>
      </div>
    </div>
    <br />
    {% if request.user == u %}
    <div class="row">
      <div class="col-md-6">
        <div class="card card-signin my-5">
          <div class="card-body">
            <h2>Friend Requests Sent ({{ sent_friend_requests.count }})</h2>
            <hr class="my-2" />
            {% if not sent_friend_requests %}
            <h5><i>No sent requests!</i></h5>
            {% else %} {% for s_request in sent_friend_requests %}
            <a href="{{ s_request.to_user.profile.get_absolute_url }}"
              ><img
                src="{{ s_request.to_user.profile.image.url }}"
                class="rounded mr-2"
                width="40"
                height="40"
                alt=""
            /></a>
            <a href="{{ s_request.to_user.profile.get_absolute_url }}"
              ><b>{{ s_request.to_user.username }}</b></a
            >
            <small class="float-right">
              <a
                class="btn btn-warning mr-2"
                href="{% url 'cancel_friend_request' s_request.to_user.id %}"
                >Cancel</a
              >
            </small>
            <br /><br />
            {% endfor %} {% endif %}
          </div>
        </div>
      </div>
      <div class="col-md-6">
        <div class="card card-signin my-5">
          <div class="card-body">
            <h2>Friend Requests Recieved ({{ rec_friend_requests.count }})</h2>
            <hr class="my-2" />
            {% if not rec_friend_requests %}
            <h5><i>No recieved requests!</i></h5>
            {% else %} {% for r_request in rec_friend_requests %}
            <a href="{{ r_request.from_user.profile.get_absolute_url }}"
              ><img
                src="{{ r_request.from_user.profile.image.url }}"
                class="rounded mr-2"
                width="40"
                height="40"
                alt=""
            /></a>
            <a
              class="mr-2 align-middle"
              href="{{ r_request.from_user.profile.get_absolute_url }}"
              ><b>{{ r_request.from_user.username }}</b>
            </a>
            <small class="float-right">
              <a
                class="btn btn-success mr-2"
                href="/users/friend-request/accept/{{ r_request.from_user.id }}"
                >Accept</a
              >
              <a
                class="btn btn-danger"
                href="/users/friend-request/delete/{{ r_request.from_user.id }}"
                >Reject</a
              >
            </small>
            <br /><br />
            {% endfor %} {% endif %}
          </div>
        </div>
      </div>
    </div>
    {% endif %}
  </div>
</div>

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

edit_profile.html

This page contains the forms we require to update our profile. We can update our email, username, profile picture and bio. It has a submit button to update the profile and take us back to the profile page.

{% extends "feed/layout.html" %} {% load static %} {% block cssfiles %} {%
endblock cssfiles %} {% block searchform %}
<form
  class="form-inline my-2 my-lg-0 ml-5"
  action="{% url 'search_users' %}"
  method="get"
>
  <input name="q" type="text" placeholder="Search users.." />
  <button class="btn btn-success my-2 my-sm-0 ml-4" type="submit">
    Search
  </button>
</form>
{% endblock searchform %} {% load crispy_forms_tags %} {% block content %}
<br /><br />
<div class="container">
  <div class="row">
    <div class="col-sm-9 col-md-8 col-lg-7 mx-auto">
      <div class="card card-signin my-5">
        <div class="card-body">
          <h5 class="card-title text-center"><b>Update Profile</b></h5>
          <form class="form-signin" method="POST" enctype="multipart/form-data">
            {% csrf_token %}
            <fieldset class="form-group">
              <br />
              {{ u_form|crispy }} {{ p_form|crispy }}
            </fieldset>
            <div class="form-group">
              <button
                class="btn btn-lg btn-primary btn-block text-uppercase"
                type="submit"
              >
                Update</button
              ><br /><br />
              <a
                class="btn btn-lg btn-warning btn-block text-uppercase"
                href="{% url 'my_profile' %}"
                >Go Back</a
              >
            </div>
          </form>
        </div>
      </div>
    </div>
  </div>
</div>
{% endblock content %} {% block jsfiles %}{% endblock jsfiles %}
Enter fullscreen mode Exit fullscreen mode

friend_list.html

Here we display all our friends and we get an option to unfriend them. All our friends are displayed as a list. We also display a card containing the current user’s info in the side.

{% extends "feed/layout.html" %} {% load static %} {% block cssfiles %} {%
endblock cssfiles %} {% block searchform %}
<form
  class="form-inline my-2 my-lg-0 ml-5"
  action="{% url 'search_users' %}"
  method="get"
>
  <input name="q" type="text" placeholder="Search users.." />
  <button class="btn btn-success my-2 my-sm-0 ml-4" type="submit">
    Search
  </button>
</form>
{% endblock searchform %} {% block content %}
<div class="container">
  <div class="row">
    <div class="col-md-8">
      {% if friends %}
      <div class="card card-signin my-5">
        <div class="card-body">
          {% for user_p in friends %}
          <a href="{{ user_p.get_absolute_url }}"
            ><img
              src="{{ user_p.image.url }}"
              class="rounded mr-2"
              width="40"
              height="40"
              alt=""
          /></a>
          <a class="text-dark" href="{{ user_p.get_absolute_url }}"
            ><b>{{ user_p }}</b></a
          >
          <small
            ><a
              class="btn btn-danger float-right"
              href="{% url 'delete_friend' user_p.id %}"
              >UnFriend</a
            ></small
          >
          <br /><br />
          {% endfor %}
        </div>
      </div>
      {% else %}
      <h5>
        <i
          >You have no friends now! Make some new
          <a href="{% url 'users_list' %}">friends here!</a></i
        >
      </h5>
      {% endif %}
    </div>
    <div class="col-md-4">
      <div class="card card-signin my-5">
        <a href="{{ request.user.profile.get_absolute_url }}"
          ><img
            class="card-img-top"
            src="{{ request.user.profile.image.url }}"
            alt=""
        /></a>
        <div class="card-body">
          <h5 class="card-title text-center">{{ request.user }}</h5>
          <h6 class="text-center">
            {{ request.user.profile.friends.count }}
            <p class="text-muted">Friends</p>
          </h6>
          <p class="card-text text-center">{{ request.user.profile.bio }}</p>
        </div>
      </div>
    </div>
  </div>
  {% endblock content %} {% block jsfiles %}{% endblock jsfiles %}
</div>
Enter fullscreen mode Exit fullscreen mode

search_users.html

This page displays all the users who came up when we use the search bar to search for users using their names. This list contains all the search results and we have an option. We also display a card containing the current user’s info in the side.

{% extends "feed/layout.html" %}{%
endblock cssfiles %} {% block searchform %}
<form
  class="form-inline my-2 my-lg-0 ml-5"
  action="{% url 'search_users' %}"
  method="get"
>
  <input name="q" type="text" placeholder="Search users.." />
  <button class="btn btn-success my-2 my-sm-0 ml-4" type="submit">
    Search
  </button>
</form>
{% endblock searchform %} {% block content %}
<div class="container">
  <div class="row">
    <div class="col-md-8">
      {% if not users %}
      <br /><br />
      <h2><i>No such users found!</i></h2>
      {% else %}
      <div class="card card-signin my-5">
        <div class="card-body">
          {% for user_p in users %}
          <a href="{{ user_p.profile.get_absolute_url }}"
            ><img
              src="{{ user_p.profile.image.url }}"
              class="rounded mr-2"
              width="40"
              height="40"
              alt=""
          /></a>
          <a class="text-dark" href="{{ user_p.profile.get_absolute_url }}"
            ><b>{{ user_p }}</b></a
          >
          <br /><br />
          {% endfor %}
        </div>
      </div>
      {% endif %}
    </div>
    <div class="col-md-4">
      <div class="card card-signin my-5">
        <a href="{{ request.user.profile.get_absolute_url }}"
          ><img
            class="card-img-top"
            src="{{ request.user.profile.image.url }}"
            alt=""
        /></a>
        <div class="card-body">
          <h5 class="card-title text-center">{{ request.user }}</h5>
          <h6 class="text-center">
            {{ request.user.profile.friends.count }}
            <p class="text-muted">Friends</p>
          </h6>
          <p class="card-text text-center">{{ request.user.profile.bio }}</p>
        </div>
      </div>
    </div>
  </div>
  {% endblock content %}
</div>
Enter fullscreen mode Exit fullscreen mode

users_list.html

This list contains the users recommended to add as friends. Its to look and find new people and increase your friends. We also have the option to Add Friend or Cancel Request for all those users. We also display a card containing the current user’s info in the side.

{% extends "feed/layout.html" %} {% load static %} {% block cssfiles %} {%
endblock cssfiles %} {% block searchform %}
<form
  class="form-inline my-2 my-lg-0 ml-5"
  action="{% url 'search_users' %}"
  method="get"
>
  <input name="q" type="text" placeholder="Search users.." />
  <button class="btn btn-success my-2 my-sm-0 ml-4" type="submit">
    Search
  </button>
</form>
{% endblock searchform %} {% block content %}
<div class="container">
  <div class="row">
    <div class="col-md-8">
      {% if users %}
      <div class="card card-signin my-5">
        <div class="card-body">
          {% for user_p in users %}
          <a href="{{ user_p.get_absolute_url }}"
            ><img
              src="{{ user_p.image.url }}"
              class="rounded mr-2"
              width="40"
              height="40"
              alt=""
          /></a>
          <a class="text-dark" href="{{ user_p.get_absolute_url }}"
            ><b>{{ user_p }}</b></a
          >
          {% if not user_p.user in sent %}
          <small class="float-right">
            <a
              class="btn btn-primary mr-2"
              href="{% url 'send_friend_request' user_p.id %}"
              >Add Friend</a
            >
          </small>
          {% else %}
          <small class="float-right">
            <a
              class="btn btn-warning mr-2"
              href="{% url 'cancel_friend_request' user_p.id %}"
              >Cancel Request</a
            >
          </small>
          {% endif %}
          <br /><br />
          {% endfor %}
        </div>
      </div>
      {% else %}
      <h5><i>No new people to add now! Please come back later!</i></h5>
      {% endif %}
    </div>
    <div class="col-md-4">
      <div class="card card-signin my-5">
        <a href="{{ request.user.profile.get_absolute_url }}"
          ><img
            class="card-img-top"
            src="{{ request.user.profile.image.url }}"
            alt=""
        /></a>
        <div class="card-body">
          <h5 class="card-title text-center">{{ request.user }}</h5>
          <h6 class="text-center">
            {{ request.user.profile.friends.count }}
            <p class="text-muted">Friends</p>
          </h6>
          <p class="card-text text-center">{{ request.user.profile.bio }}</p>
        </div>
      </div>
    </div>
  </div>
  {% endblock content %} {% block jsfiles %}{% endblock jsfiles %}
</div>
Enter fullscreen mode Exit fullscreen mode

So, that’s all for the Users App Templates. It was a lot of HTML content. Hope you are not bored. But, we had to do it to keep the tutorial in a coherent manner. We have two parts left now where would be discussing the Feeds app and its templates. Those will handle all the logic and rendering of the posts, likes, comments etc.

Hope, you enjoyed reading the tutorial. Thanks a lot!

Top comments (0)