Grocery Bag using Django (Part-2) - Fixing Templates and Static Files

Introduction

In the last part, we had set up our GroceryBag project. In this part, we will fix our templates and static files URLs in the templates. The problem is, if you look at the templates, the code is similar in all of the files. We can fix this problem using Template Inheritance. Inheritance means to get something from another, i.e. the child(one which is inheriting) gets the properties from its parent(one which is being inherited). We use Template Inheritance to avoid writing the same HTML code again and again in various files.

The next thing we are going to fix is the way we are linking the static files with these templates. Let's fix this problem first, then we'll move to Template Inheritance.

Fixing Static Files URLs

Until now, we're linking the static files(CSS, Images, and JavaScript) with the templates in this way:

<link rel="stylesheet" href="css/style.css" />

But this won't be working if you have put the template files and static files in their respective directories correctly. If you remember, in the previous blog, we had added STATIC_URL and STATICFILES_DIR in our GroceryBag/settings.py as this one:

STATIC_URL = '/static/'

STATICFILES_DIRS = [
    BASE_DIR / "static",
]

With these configurations in place, we are ready to serve the static files dynamically in the templates using this syntax:

{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}" />

You can learn more about these in the official documentation of Django.

Django Template Inheritance

As we know, we use Template Inheritance to avoid writing the same HTML code again and again in various files. Suppose, you have a few things that are common in all the web pages. What we can do is, instead of writing the code, again and again, we can write the common code in a base.html file and then extend this file in other HTML templates.

extends and block tags

The extends tag is used to inherit a parent or base template inside a child template. The syntax looks like this:

{% extends "filename.html" %}

The filename should be the path of the base template within the templates directory.

The block tag is used to override some parts of the parent template in the child template. We can create as many blocks as we need. The syntax looks like this:

{% block block_name %}

{% endblock block_name %}

Example

Suppose we have a base template base.html as this:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>{% block title %}{% endblock title %} | Grocery Bag</title>
  </head>
  {% block content %} {% endblock content %}
</html>

We can inherit this base template and create a child template index.html as this:

{% extends "base.html" %}

{% block title %}Index Page{% endblock title %} 

{% block content %}
<body>
  Hello World!
</body>
{% endblock content %}

Fixing our templates

Now that we have learned Template Inheritance, we can create a base.html file in the templates directory and add the following content inside it:

{% load static %}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>{% block title %}{% endblock title %} | Grocery Bag</title>
    <link
      href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
      crossorigin="anonymous"
    />
<!-- JavaScript Bundle with Popper -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="{% static 'css/style.css' %}" />
    {% block custom_head %} {% endblock custom_head %}
  </head>
  {% block content %} {% endblock content %}
</html>

Notice how we linked the CSS file to the webpage. We have also created three blocks - title, custom_head and content. title will be used to supply the title from each page, custom_head will be used to add more static files required by other web pages, and content will be used to supply the body.

Now, let's fix the other webpages.

index.html

{% extends "base.html" %}{% load static %} {% block title %}View Bag{% endblock title %} 

{% block content %}
<body>
  <div class="container mt-5">
    <!-- top -->
    <div class="row">
      <div class="col-lg-6">
        <h1>View Grocery List</h1>
      </div>
      <div class="col-lg-6 float-right">
        <div class="row">
          <div class="col-lg-8">
            <!-- Date Filtering-->
            <input type="date" class="form-control" />
          </div>
          <div class="col-lg-4">
            <input type="submit" class="btn btn-danger" value="filter" />
          </div>
        </div>
      </div>
    </div>
    <!-- // top -->
    <!-- Grocery Cards -->
    <div class="row mt-4">
      <!--- -->
      <!-- Loop This -->
      <div class="col-lg-4">
        <div class="card">
          <div class="card-body">
            <h5 class="card-title">Tomato</h5>
            <h6 class="card-subtitle mb-2 text-muted">2 Pcs.</h6>
            <p class="text-success">BOUGHT</p>
          </div>
        </div>
      </div>
      <!-- // Loop -->
      <div class="col-lg-4">
        <div class="card">
          <div class="card-body">
            <h5 class="card-title">Chicken</h5>
            <h6 class="card-subtitle mb-2 text-muted">2Kgs</h6>
            <p class="text-danger">NOT AVAILABLE</p>
          </div>
        </div>
      </div>

      <div class="col-lg-4">
        <div class="card">
          <div class="card-body">
            <h5 class="card-title">Posto</h5>
            <h6 class="card-subtitle mb-2 text-muted">50gms</h6>
            <p class="text-info">PENDING</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</body>
{% endblock content %}

add.html

{% extends "base.html" %}{% load static %} {% block title %}Add to bag{% endblock title %} 

{% block content %}
<body>
  <div class="container mt-5">
    <h1>Add to Grocery Bag</h1>
    <form>
      <div class="form-group mt-2">
        <label>Item name</label>
        <input type="text" class="form-control" placeholder="Item name" />
      </div>
      <div class="form-group mt-2">
        <label>Item quantity</label>
        <input type="text" class="form-control" placeholder="Item quantity" />
      </div>
      <div class="form-group mt-2">
        <label>Item status</label>
        <select class="form-control">
          <option value="0">PENDING</option>
          <option value="1">BOUGHT</option>
          <option value="0">NOT AVAILABLE</option>
        </select>
      </div>
      <div class="form-group mt-2">
        <label>Date</label>
        <input type="date" class="form-control" placeholder="Date" />
      </div>
      <div class="form-group mt-2">
        <input type="submit" value="Add" class="btn btn-danger" />
      </div>
    </form>
  </div>
</body>
{% endblock content %}

update.html

{% extends "base.html" %}{% load static %} {% block title %}Update bag{% endblock title %} 

{% block content %}
<body>
  <div class="container mt-5">
    <h1>Update Grocery Bag</h1>
    <form>
      <div class="form-group mt-2">
        <label>Item name</label>
        <input
          type="text"
          class="form-control"
          placeholder="Item name"
          value="TOMATO"
        />
      </div>
      <div class="form-group mt-2">
        <label>Item quantity</label>
        <input
          type="text"
          class="form-control"
          placeholder="Item quantity"
          value="2PCS"
        />
      </div>
      <div class="form-group mt-2">
        <label>Item status</label>
        <select class="form-control">
          <option value="0">PENDING</option>
          <option value="1" selected>BOUGHT</option>
          <option value="0">NOT AVAILABLE</option>
        </select>
      </div>
      <div class="form-group mt-2">
        <label>Date</label>
        <input
          type="date"
          class="form-control"
          placeholder="Date"
          value="2020-03-20"
        />
      </div>
      <div class="form-group mt-2">
        <input type="submit" value="Update" class="btn btn-danger" />
      </div>
    </form>
  </div>
</body>
{% endblock content %}

signin.html

{% extends "base.html" %}{% load static %} {% block title %} Sign In {% endblock title %} 

{% block custom_head %}
<link rel="stylesheet" href="{% static 'css/signin.css' %}" />
{% endblock custom_head %} 

{% block content %}
<body class="text-center">
  <main class="form-signin">
    <form>
      <h1 class="h3 mb-3 fw-normal">Please sign in</h1>

      <div class="form-floating mt-2">
        <input
          type="text"
          class="form-control"
          id="floatingInput"
          name="username"
          placeholder="johndoe"
        />
        <label for="floatingInput">Username</label>
      </div>
      <div class="form-floating mt-2">
        <input
          type="password"
          class="form-control"
          id="floatingPassword"
          name="password"
          placeholder="Password"
        />
        <label for="floatingPassword">Password</label>
      </div>

      <button class="w-100 btn btn-lg btn-primary" type="submit">
        Sign in
      </button>
      <p class="mt-3">New user? <a href="signup.html">Sign up now</a></p>
    </form>
  </main>
</body>
{% endblock content %}

signup.html

{% extends "base.html" %}{% load static %} {% block title %} Sign Up {% endblock title %} 

{% block custom_head %}
<link rel="stylesheet" href="{% static 'css/signin.css' %}" />
{% endblock custom_head %} 

{% block content %}
<body class="text-center">
  <main class="form-signin">
    <form>
      <h1 class="h3 mb-3 fw-normal">Please sign up</h1>

      <div class="form-floating mt-2">
        <input
          type="text"
          class="form-control"
          id="floatingInput"
          name="username"
          placeholder="johndoe"
        />
        <label for="floatingInput">Username</label>
      </div>
      <div class="form-floating mt-2">
        <input
          type="password"
          class="form-control"
          id="floatingPassword"
          name="password"
          placeholder="Password"
        />
        <label for="floatingPassword">Password</label>
      </div>

      <button class="w-100 btn btn-lg btn-primary" type="submit">
        Sign up
      </button>
      <p class="mt-3">
        Already Registered? <a href="signin.html">Sign in now</a>
      </p>
    </form>
  </main>
</body>
{% endblock content %}

Running the server

Before we run the server, let's add a view function in the bag/views.py as this:

from django.shortcuts import render

# Create your views here.
def index(request):
    return render(request, "index.html")

Also, add the view in the bag/urls.py:

from django.urls import path

from bag.views import index

urlpatterns = [
    path('', index, name='index'),
]

Now we're ready to run the server using the command:

$ py manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
November 25, 2021 - 18:57:25
Django version 3.2.9, using settings 'GroceryBag.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

If you open the URL in your favorite browser, you will see this output:

This means we have everything working correctly. Similarly, you can replace index.html with other template files in the bag/views.py to test other web pages.

Conclusion

In this blog, we have learned about Template Inheritance and how to serve static files. We have fixed our templates now. In the next blog, we'll see how we can authenticate the user into our web app. Stay tuned!

22