Skip to ContentGo to accessibility pageKeyboard shortcuts menu
OpenStax Logo
Introduction to Computer Science

11.2 Sample Responsive WAD with Bootstrap and Django

Introduction to Computer Science11.2 Sample Responsive WAD with Bootstrap and Django

Learning Objectives

By the end of this section, you will be able to:

  • Create a Todo web application with Bootstrap and Django
  • Create a Django project
  • Create and register a Todo app
  • Define the Todo model
  • Set up the Django REST APIs
  • Create the user interface

In this module, you will create a simple, responsive Todo application. To accomplish this, you will use Bootstrap and Django. Bootstrap is an open-source, responsive web application framework, and Django is a Python-based web application development framework. Both frameworks are highly popular due to their ease of use.

Creating a Todo Web Application with Bootstrap and Django

The Todo web application in this subsection uses Bootstrap and Django. Bootstrap’s CSS templates are used for the UI features. Django serves as both the front end and back end. Django templates are part of the user interface to get and set data via HTTP requests. Incoming requests are then handled by an API built using the Django REST Framework.

Prerequisites

To build the Todo application, you must install Python, PIP, Django, Django REST Framework, Bootstrap, and jQuery. The Todo application on the following pages was developed and tested with specific software versions. To avoid errors, please ensure you install the same versions: Python v3.9.4, PIP v21.3.1, Django v4.0.1, Django REST Framework v3.13.1, Bootstrap v4.5.0, and jQuery v3.5.1.

The steps to build the Todo application are as follows:

  • Install and set up a local programming environment for Python 3.
  • Download and install Python 3.9.4.
  • Figure 11.14 shows adding Python and its Scripts subfolder to your path environment data (on Windows, the path updates might be: C:\Users\your_username\AppData\Local\Programs\Python\Python39 and C:\Users\your_username\AppData\Local\Programs\Python\Python39\Scripts).
    Edit environment variable window shows adding Python and its Scripts folders.
    Figure 11.14 This is what appears when adding Python and its Scripts folders to the environment variables path on Windows. (Used with permission from Microsoft.)
  • Create a Python venv:
    $ python -m venv py394venv
  • Activate the venv:
    $ cd py394venv
    Windows: $ .\Scripts\activate.bat
    macOS: $ source ./bin/activate
  • Install in the local programming environment Django:
    $ pip install Django==4.0.1
  • Install in the local programming environment Django REST Framework:
    $ pip install djangorestframework==3.13.1]

Figure 11.15 shows the sequence of steps needed to install the Python environment for working with Django and the Django REST Framework.

Sequence of steps needed to install the Python environment.
Figure 11.15 This screenshot displays the sequence of steps needed to install the Python environment. (Used with permission from Microsoft)

Creating the Django Project

The first step to building a Django web application is to create a Django project, which is a high-level directory used to contain the directories and files necessary to run a Django web application. To create a Django project, run the following commands:

$ mkdir BootstrapDjangoToDoApp
$ cd BootstrapDjangoToDoApp
$ django-admin startproject ToDoApp.

The period at the end of the last command is very important to ensure that Django-dependent files are generated in the current directory. By following these commands, the directory, BootstrapDjangoToDoApp/, will be created and Django-dependent files will be generated as shown in Figure 11.16.

Directory BootstrapDjanoToDoApp includes Django-dependent files: _pycache_, static, _init_.py, asgi.py, settings.py, urls.py, wsgi.py, db.sqlite3, manage.py.
Figure 11.16 The directory BootstrapDjangoToDoApp/ includes these Django-dependent files. (rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)

Django built-in database tables are used to manage users, groups, migrations, and so forth in a web application. To generate these tables, run the migrate command:

$ python manage.py migrate

The final step to creating a Django project is to confirm that the setup was completed. To do this, run the runserver command shown here:

$ python manage.py runserver

To further confirm that the Django project setup was completed, launch a browser and navigate to http://localhost:8000. Figure 11.17 shows the Django page.

Django page shown once project setup is complete: The install worked successfully! Congratulations!
Figure 11.17 Once the Django project setup is successfully completed, this page should appear at http://localhost:8000. (credit: Django is a registered trademark of the Django Software Foundation.)

Creating and Registering the Todo App

Once the Django project is successfully completed and set up, the next step is to create the Todo application and register it in the Django project. To accomplish this, run the following command:

$ python manage.py startapp todo

The todo/ directory will be generated under the Django project directory, BootstrapDjangoToDoApp/. Files related to the Todo application will be generated as shown in Figure 11.18.

Todo/ directory generated under the Django project directory: _pycache_, migrations, static, _init_.py, admin.py, apps.py, models.py, tests.py, urls.py, views.py.
Figure 11.18 This shows the todo/ directory, which is generated under the Django project directory, BootstrapDjangoToDoApp/. (rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)

Next, the Todo application must be registered in the Django project as an installed app so that Django can recognize it. To do this, open the ToDoApp/settings.py file. Look for the INSTALLED_APPS variable as seen in Figure 11.19. Add ‘todo’ to the list as shown. Because the Django REST Framework will be used, also add ‘rest_framework’ to the list.

A list of installed apps includes ‘rest_framework’ and ‘todo’.
Figure 11.19 To register the Todo application in the Django project as an installed app, the list of installed apps should include ‘rest_framework’ and ‘todo’. (rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)

Define the Todo Model

Once you register and install the ToDo web application, you will be able to create todo tasks, which can be assigned categories. The next step is to create the models. Two models will be created for Category and TodoList. Open the todo/models.py file and add the code shown.

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models
from django.utils import timezone

# Create your models here.
class Category(models.Model):

  name = models.CharField(max_length=100)

  class Meta:
    verbose_name = ("Category")
    verbose_name_plural = ("Categories")

  def __str__(self):
    return self.name

class TodoList(models.Model):
  title = models.CharField(max_length=250)
  content = models.TextField(blank=True)
  created = models.DateField(default=timezone.now().strftime("%Y-%m-%d"))
  due_date = models.DateField(default=timezone.now().strftime("%Y-%m-%d"))
  category = models.ForeignKey(Category, default="General", on_delete=models.DO_NOTHING)
  class Meta:
    ordering = ["-created"] # order by most recently created
  def __str__(self):
    return self.title

The Category and TodoList Python classes describe the properties for the models for Category and TodoList tables, respectively. The TodoList model contains a ForeignKey field to the Category model. Each todo item will be associated with one category. After creating the models, a migration file needs to be generated to create the physical tables in the database. To generate the migration file, run the following command:

    $ python manage.py makemigrations todo
    

This command will generate a migration file in todo/migrations/, which will look like the following code.

# Generated by Django 4.0.1 on 2022-01-30 21:14

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

  initial = True

  dependencies = [
  ]

  operations = [
     migrations.CreateModel(
        name='Category',
        fields=[
           ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
           ('name', models.CharField(max_length=100)),
        ],
        options={
           'verbose_name': 'Category',
           'verbose_name_plural': 'Categories',
        },
     ),
     migrations.CreateModel(
        name='TodoList',
        fields=[
           ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
           ('title', models.CharField(max_length=250)),
           ('content', models.TextField(blank=True)),
           ('created', models.DateField(default='2022-01-30')),
           ('due_date', models.DateField(default='2022-01-30')),
           ('category', models.ForeignKey(default='General', on_delete=django.db.models.deletion.DO_NOTHING, to='todo.category')),
        ],
        options={
           'ordering': ['-created'],
        },
     ),
  ]

The next step is to apply the changes in the migration file to the database, which is accomplished by running the following command:

$ python manage.py migrate

For this application, Django uses the default sqlite3 (db.sqlite3) database. Please note that Django supports other databases as well, including MySQL and PostgreSQL. To define the Todo model, you can use the default Django admin interface to perform CRUD operations on the database. To use the admin interface, open the todo/admin.py file and register the models as seen in the following code snippet.

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.contrib import admin
from . import models

# Register your models here.
class TodoListAdmin(admin.ModelAdmin):
  list_display = ("title", "created", "due_date")

class CategoryAdmin(admin.ModelAdmin):
  list_display = ("name",)

admin.site.register(models.TodoList, TodoListAdmin)
admin.site.register(models.Category, CategoryAdmin)

The next step is to create a superuser account that allows access to the admin interface. To do this, run the following command and follow the prompts to enter a username, email address, and password for the superuser.

$ python manage.py createsuperuser

Once this step is complete, restart the server using the following command:

$ python manage.py runserver

After this is complete, open a browser and navigate to http://localhost:8000/admin/. To access the admin interface, log in with the credentials that you set up for the superuser. When you log in to the admin interface, you should see the following page from Figure 11.20. On this page, you will have the ability to create, edit, and delete categories and todo items.

The Django administration interface shows site administration tools to create, edit, and delete categories and todo items.
Figure 11.20 The admin interface is where superusers can create, edit, and delete categories and todo items in the Todo web application. (rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)

Setting Up the Django REST APIs

Previously, you installed the Django REST Framework, which provides a toolkit to build APIs. In this section, you’ll create the serializers, View functions, and routers required for the API.

Creating the Serializers

The next step is to implement two serializers, one for the Category model and one for the TodoList model. A serializer is a tool to control response outputs and convert complex data into content, such as JSON. In the todo/ directory, create the file, serializers.py, and add the code shown in the code snippet that follows. The serializer classes inherit from serializers.ModelSerializer because this class creates the serializer, with fields corresponding to the Model fields defined earlier. Each serializer specifies the Model to work with and the fields to be included in the JSON object, which are all fields.

# todo/serializers.py

from rest_framework import serializers
from .models import TodoList, Category

class CategorySerializer(serializers.ModelSerializer):
  class Meta:
    model = Category
    fields = "__all__"

class TodoSerializer(serializers.ModelSerializer):
  class Meta:
    model = TodoList
    fields = "__all__"

Creating the View

After you create each serializer, the next step is to create a corresponding View function for both the Category serializer and the Todo serializer. To do this, open todo/views.py and add the code shown in the code snippet that follows. The viewsets class, which provides a default implementation of the CRUD operations, is imported from rest_framework. The CategoryView and TodoView classes provide a queryset of categories and todo items, respectively. They also specify the serializer_class defined in the previous section.

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.shortcuts import render,redirect
from rest_framework import viewsets
from .serializers import TodoSerializer, CategorySerializer
from .models import TodoList, Category
import datetime

# Create your views here.

class CategoryView(viewsets.ModelViewSet):
  queryset = Category.objects.all()
  serializer_class = CategorySerializer

class TodoView(viewsets.ModelViewSet):
  queryset = TodoList.objects.all()
  serializer_class = TodoSerializer

Creating the Routers

The next step is to create the routers that provide URL paths for the API. To do this, open the todo/urls.py file and add the code shown in the code snippet that follows:

from django.urls import path, include
#from todo import views as todo_views
from rest_framework import routers
from todo.views import *

router = routers.DefaultRouter()
router.register(r'categories', CategoryView, basename='Categories')
router.register(r'todos', TodoView, basename='Todos')

urlpatterns = [
  path('', index, name="TodoList"),
  path(r'api/', include(router.urls)),
]

Once you complete this step, launch the Django server using the following command:

    $ python manage.py runserver
    

To access the API, launch a browser and navigate to http://127.0.0.1:8000/api/. As shown in Figure 11.21, you should see two API paths listed, one for categories and another for todo items.

Screenshot of API paths – one for categories and one for todo items.
Figure 11.21 Once the URL paths for the API are created, two API paths are listed—one path for categories and the other for todo. (rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)

Todo items are dependent on categories. To perform CRUD operations on the Category table, click on the categories API path, as shown in Figure 11.22.

Screenshot of Category List with API path.
Figure 11.22 The API path can be used to perform CRUD operations on the Category table. (rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)

Once you access the Category List page, enter a category name in the field near the bottom of the page and click the Post button to save it. You can add additional category names. Once you save each name using the Post button, the categories will appear in JSON format, as illustrated in Figure 11.23.

Screenshot of JSON format on Category List.
Figure 11.23 The Category List is created in JSON format after saving category names. (rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)

To ensure that categories can be updated or deleted as needed, the primary key, which is “id”, must be included in the API path (e.g., /api/categories/{id}/). For example, to update or delete the category with id=3, the API path is /api/categories/3/. As shown in Figure 11.24, once this category is pulled up on the Category Instance page, the DELETE button is visible at the top to delete the category. If the category needs to be updated, the PUT button visible near the bottom can be used for updates.

Screenshot of Category Instance displaying DELETE and PUT buttons.
Figure 11.24 The Category Instance page provides DELETE and PUT buttons, which, respectively, can be used to delete or update a category. (rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)

Next, navigate back to the API root. Click on the todos API path to see, as outlined in Figure 11.25, that a Todo item has a Category field that appears as a drop-down list of categories. The CRUD operations also can be performed on the TodoList table. This will be done next through the user interface via templates.

Screenshot of Todo List with drop down category showing Work and Personal.
Figure 11.25 After the routers are created, a Todo item has a Category field that appears as a drop-down list of categories, such as “Work” and “Personal.” (rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)

Creating the User Interface

To use and control the Todo application, you must create a user interface (UI). This section will outline the steps to do this.

Installing Bootstrap

The first step to create a UI is to install Bootstrap, which, as an open-source, responsive web application framework, can be used in web applications like Django to create UIs. To install Bootstrap in a Django application, you have several options. In this scenario, an efficient method is to download the Bootstrap CSS and JS files and add them to the static/ directory, as shown in Figure 11.26. To do this, first create the static/ directory in the Django project directory. In addition, to install jQuery, download the JS file and add it to the static/ directory. Finally, add a custom CSS file to include individual style in the Django web application.

Screenshot of static directory with css and js files listed.
Figure 11.26 An efficient method to install Bootstrap in a Django application is to download the Bootstrap CSS and JS files and add them to the static/ directory. (rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)

After adding the CSS and JS files to the static/ directory, the next step is to open the ToDoApp/settings.py file, navigate to the bottom of the file, and add the path variables shown in the following code snippet.

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.0/howto/static-files/

STATIC_URL = 'static/'

PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static')

Creating the View

The next step is to create the View. The View function is needed for template pages, which are created in the next section. The View function is also needed to interact with the database to both create and delete todo items.

To create the View, open the todo/views.py file and add the code shown in the following code snippet. This code takes an HTTP request object. If the request method is POST, a todo item is either created or deleted, depending on which button is clicked. Otherwise, the request method is GET and the todo items are displayed to the user.

def index(request): # index view
  todos = TodoList.objects.all() # query all todos with object manager
  categories = Category.objects.all() # get all categories with object manager
  if request.method == "POST": # check if request method is POST
    if "taskAdd" in request.POST: # check if request is to add a todo item
      title = request.POST["description"] # title
      date = str(request.POST["date"]) # date
      category = request.POST["category_select"] # category
      content = title + " -- " + date + " " + category # content
      Todo = TodoList(title=title, content=content, due_date=date, category=Category.objects.get(name=category))
      Todo.save() # save todo item
      return redirect("/") # reload page
    if "taskDelete" in request.POST: # check if request is to delete a todo
      checkedlist = request.POST["checkedbox"] # checked todos to be deleted
      for todo_id in checkedlist:
        todo = TodoList.objects.get(id=int(todo_id)) # get todo id
        todo.delete() # delete todo
  return render(request, "index.html", {"todos": todos, "categories":categories})

Creating the Templates

The final step to build a Django web application is to create templates, which are HTML files that can also contain embedded Python code. Create a file called style.css under the /static/css directory and insert the code shown here into that file. The templates discussed in the following sections require this style sheet.

/* basic reset */
*,
*:before,
*:after {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

/* app */
html {
  font-size: 100%;
}

body {
  background: #e6f9ff;
  font-family: "Open Sans", sans-serif;
}
/* super basic grid structure */
.container {
  width: 600px;
  margin: 0 auto;
  background: #ffffff;
  padding: 20px 0;
  -webkit-box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
  box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
}

.row {
  display: block;
  padding: 10px;
  text-align: center;
  width: 100%;
  clear: both;
  overflow: hidden;
}

.half {
  width: 50%;
  float: left;
}

.content {
  background: #fff;
}

/* logo */
h1 {
  font-family: "Rokkitt", sans-serif;
  color: #666;
  text-align: center;
  font-weight: 400;
  margin: 0;
}

.tagline {
  margin-top: -10px;
  text-align: center;
  padding: 5px 20px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  color: #777;
}

/* inputs */
.inputContainer {
  height: 60px;
  border-top: 1px solid #e5e5e5;
  position: relative;
  overflow: hidden;
}

.inputContainer.last {
  border-bottom: 1px solid #e5e5e5;
  margin-bottom: 20px;
}

.inputContainer.half.last.right {
  border-left: 1px solid #efefef;
}

input[type="date"],
input[type="text"],
select {
  height: 100%;
  width: 100%;
  padding: 0 20px;
  position: absolute;
  top: 0;
  vertical-align: middle;
  display: inline-block;
  border: none;
  border-radius: none;
  font-size: 13px;
  color: #777;
  margin: 0;
  font-family: "Open Sans", sans-serif;
  font-weight: 600;
  letter-spacing: 0.5px;
  -webkit-transition: background 0.3s;
  transition: background 0.3s;
}

input[type="date"] {
  cursor: pointer;
}

input[type="date"]:focus,
input[type="text"]:focus,
select:focus {
  outline: none;
  background: #ecf0f1;
}

::-webkit-input-placeholder {
  color: lightgrey;
  font-weight: normal;
  -webkit-transition: all 0.3s;
  transition: all 0.3s;
}
::-moz-placeholder {
  color: lightgrey;
  font-weight: normal;
  transition: all 0.3s;
}
::-ms-input-placeholder {
  color: lightgrey;
  font-weight: normal;
  transition: all 0.3s;
}
input:-moz-placeholder {
  color: lightgrey;
  font-weight: normal;
  transition: all 0.3s;
}

input:focus::-webkit-input-placeholder {
  color: #95a5a6;
  font-weight: bold;
}

input:focus::-moz-input-placeholder {
  color: #95a5a6;
  font-weight: bold;
}

.inputContainer label {
  padding: 5px 20px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  color: #777;
  display: block;
  position: absolute;
}

button {
  font-family: "Open Sans", sans-serif;
  background: transparent;
  border-radius: 2px;
  border: none;
  outline: none;
  height: 50px;
  font-size: 14px;
  color: #fff;
  cursor: pointer;
  text-transform: uppercase;
  position: relative;
  -webkit-transition: all 0.3s;
  transition: all 0.3s;
  padding-left: 30px;
  padding-right: 15px;
}

.icon {
  position: absolute;
  top: 30%;
  left: 10px;
  font-size: 20px;
}

.taskAdd {
  background: #444;
  padding-left: 31px;
}

.taskAdd:hover {
  background: #303030;
}

.taskDelete {
  background: #e74c3c;
  padding-left: 30px;
}

.taskDelete:hover {
  background: #c0392b;
}

/* task styles */
.taskList {
  list-style: none;
  padding: 0 20px;
}

.taskItem {
  border-top: 1px solid #e5e5e5;
  padding: 15px 0;
  color: #777;
  font-weight: 600;
  font-size: 14px;
  letter-spacing: 0.5px;
}

.taskList .taskItem:nth-child(even) {
  background: #fcfcfc;
}

.taskCheckbox {
  margin-right: 1em;
}

.complete-true {
  text-decoration: line-through;
  color: #bebebe;
}

.taskList .taskDate {
  color: #95a5a6;
  font-size: 10px;
  font-weight: bold;
  text-transform: uppercase;
  display: block;
  margin-left: 41px;
}

.fa-calendar {
  margin-right: 10px;
  font-size: 16px;
}

[class*="category-"] {
  display: inline-block;
  font-size: 10px;
  background: #444;
  vertical-align: middle;
  color: #fff;
  padding: 10px;
  width: 75px;
  text-align: center;
  border-radius: 2px;
  float: right;
  font-weight: normal;
  text-transform: uppercase;
  margin-right: 20px;
}

.category- {
  background: transparent;
}

.category-Personal {
  background: #2980b9;
}

.category-Work {
  background: #8e44ad;
}

.category-School {
  background: #f39c12;
}

.category-Cleaning {
  background: #16a085;
}

.category-Other {
  background: #d35400;
}

footer {
  text-align: center;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  color: #777;
}

footer a {
  color: #f39c12;
}
/* custom checkboxes */
.taskCheckbox {
  -webkit-appearance: none;
  appearance: none;
  -webkit-transition: all 0.3s;
  transition: all 0.3s;
  display: inline-block;
  cursor: pointer;
  width: 19px;
  height: 19px;
  vertical-align: middle;
}

.taskCheckbox:focus {
  outline: none;
}

.taskCheckbox:before,
.taskCheckbox:checked:before {
  font-family: "FontAwesome";
  color: #444;
  font-size: 20px;
  -webkit-transition: all 0.3s;
  transition: all 0.3s;
}

.taskCheckbox:before {
  content: "\f096";
}

.taskCheckbox:checked:before {
  content: "\f14a";
  color: #16a085;
}
/* custom select menu */
.taskCategory {
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  padding-left: 16.5px; /*specific positioning due to difficult behavior of select element*/
  background: #fff;
}

.selectArrow {
  position: absolute;
  z-index: 10;
  top: 35%;
  right: 0;
  margin-right: 20px;
  color: #777;
  pointer-events: none;
}

.taskCategory option {
  background: #fff;
  border: none;
  outline: none;
  padding: 0 100px;
}

The first template file is base.html, which is the file that includes links to Bootstrap and jQuery. To illustrate these links, a snippet of the base.html file is shown in the code. The Bootstrap navigation bar is implemented in this file.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>TodoApp - Django</title>
    {% load static %}
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="/static/css/bootstrap.min.css" />
    <link
      rel="stylesheet"
      type="text/css"
      href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
    />
    <link
      rel="stylesheet"
      type="text/css"
      href="{% static 'css/style.css' %}"
    />
    <!-- jQuery -->
    <script
      type="text/javascript"
      src="{% static 'js/jquery-3.5.1.min.js' %}"></script>
    <!-- Popper -->
    <script
      type="text/javascript"
      src="{% static 'js/popper.min.js' %}"></script>
    <!-- Bootstrap Core JavaScript -->
    <script
    type="text/javascript"
    src="{% static 'js/bootstrap.bundle.min.js' %}"></script>
<script
</head>

<body>
  <nav class="navbar navbar-dark bg-dark justify-content-between">
    <a class="navbar-brand">ToDo</a>
    <form class="form-inline">
      <input
        class="form-control mr-sm-2"
        type="search"
        placeholder="Search"
        aria-label="Search"
      />
      <button class="btn btn-outline-info my-2 my-sm-0" type="submit">
        Search
        </button>
      </form>
    </nav>
    <div>{% block content %} {% endblock content %}</div>
  </body>
</html>

The second template file is index.html, which lists any existing todo items and includes the form to create or delete a todo item. A snippet of the index.html file is shown in the following code. The index.html file also extends the base.html template, which allows the Bootstrap navigation bar implemented in base.html to be inserted in this page and every page that extends it.

{% extends "./base.html" %} {% load static %} {% block content %}
 <div django-app="TaskManager">
  <div class="container mt-5">
   <div class="content">
    <h1>Todo List</h1>
    <!--<p class="tagline">Django Todo App</p>-->
    <form action="" method="post">
     {% csrf_token %}
     <!-- csrf token for basic security -->
     <div class="inputContainer">
       <input
        type="text"
        id="description"
        class="taskName"
        placeholder="What do you need to do?"
        name="description"
        required
       />
       <label for="description">Description</label>
      </div>
      <div class="inputContainer half last">
       <i class="fa fa-caret-down selectArrow"></emphasis>
       <select id="category" class="taskCategory" name="category_select">
        <option class="disabled" value="">Choose a category</option>
       {% for category in categories %}
       <option
        class=""
        value="{{ category.name }}"
        name="{{ category.name }}"
       >
        {{ category.name }}
       </option>
       {% endfor %}
      </select>
      <label for="category">Category</label>
     </div>
     <div class="inputContainer half last right">
      <input type="date" id="dueDate" class="taskDate" name="date" />
      <label for="dueDate">Due Date</label>
     </div>
     <div class="row">
      <button class="taskAdd" name="taskAdd" type="submit">
       <i class="fa fa-plus icon"></emphasis>Add task
      </button>
      <button
       class="taskDelete"
       name="taskDelete"
       formnovalidate=""
       type="submit"
       onclick="$('input#sublist').click();"
      >
       <i class="fa fa-trash-o icon"></emphasis>Delete Tasks
      </button>
     </div>
     <ul class="taskList">
      {% for todo in todos %}
      <!-- django template lang - for loop -->
      <li class="taskItem">
        <input
         type="checkbox"
         class="taskCheckbox"
         name="checkedbox"
         id="{{ todo.id }}"
         value="{{ todo.id }}"
        />
        <label for="{{ todo.id }}"
><span class="complete-">{{ todo.title }}</span></label>
        <span class="category-{{ todo.category }}"
         >{{ todo.category }}</span>
         >{{ todo.category }}</span
<strong class="taskDate"
><i class="fa fa-calendar"></emphasis>Created: {{todo.created}} - Due:
         >{{ todo.category }}</span
{{todo.due_date}}</strong>
        >{{ todo.category }}</span
       </li>
        {% endfor %}
       </ul>
       <!-- taskList -->
      </form>
     </div>
     <!-- content -->
    </div>
  <!-- container -->
</div>
{% endblock %}

The first step to access the Todo Django web application is to restart the Django server using the following command:

$ python manage.py runserver

Next, launch a browser and navigate to http://localhost:8000. The page highlighted in Figure 11.27 should appear.

Screenshot of Todo List with Description, Category, and Due Date sections as well as Add Task and Delete Tasks buttons.
Figure 11.27 Once the Django server is restarted, this page should appear at http://localhost:8000. (rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)

To create a todo list, fill out the form and click the Add Task button as shown in Figure 11.28.

Screenshot of Todo List with Description, Category, Due Date sections; Add Task, Delete Tasks buttons; and Write an article on how to create a Django Web application next to a Work button.
Figure 11.28 This figure shows how the Todo List should appear after using the Add Task button to create a todo list. (rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)

In addition, the todo item should also be viewable in the API that was created. This should appear as outlined in Figure 11.29.

Screenshot of Todo List viewable in API.
Figure 11.29 Once the todo item is created, it should be viewable in the API. (rendered in Django, a registered trademark of the Django Software Foundation; attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)
Citation/Attribution

This book may not be used in the training of large language models or otherwise be ingested into large language models or generative AI offerings without OpenStax's permission.

Want to cite, share, or modify this book? This book uses the Creative Commons Attribution License and you must attribute OpenStax.

Attribution information
  • If you are redistributing all or part of this book in a print format, then you must include on every physical page the following attribution:
    Access for free at https://openstax.org/books/introduction-computer-science/pages/1-introduction
  • If you are redistributing all or part of this book in a digital format, then you must include on every digital page view the following attribution:
    Access for free at https://openstax.org/books/introduction-computer-science/pages/1-introduction
Citation information

© Oct 29, 2024 OpenStax. Textbook content produced by OpenStax is licensed under a Creative Commons Attribution License . The OpenStax name, OpenStax logo, OpenStax book covers, OpenStax CNX name, and OpenStax CNX logo are not subject to the Creative Commons license and may not be reproduced without the prior and express written consent of Rice University.