Create Your First Django App (todo app case study)

Muhammad Ihsan
CodeX
Published in
16 min readJun 15, 2024
Photo by Glenn Carstens-Peters on Unsplash

Python is known as a multi-purpose programming language. It is called so because of its wide usage, ranging from data analysis, mathematical modeling, web applications, APIs, and more. In this article, we will use Python to create a simple todo application, and we will also use Django, a very popular web framework for Python. The todo case study is also very popular among beginners because it includes the basic functionalities of an application, namely CRUD (Create, Read, Update, Delete).

Prerequisites

Before starting, make sure you have:

  • Basic knowledge of Python
  • Basic knowledge of the terminal
  • Basic understanding of how the web works

Introduction to Django

Django has the slogan “The Web Framework for Perfectionists with Deadlines,” as it is a high-level web framework designed to make web development faster and easier. One of Django’s advantages is that it takes care of many complex aspects of web development, such as routing, database management, and security, allowing us to focus on feature development.

Setting Up the Development Environment

First, we need to ensure that Python is installed on our system. To check if Python is installed, open the terminal or command prompt and run the following command:

python --version

If you don’t have Python installed, you can download and install it from the official Python website.

Creating a Virtual Environment

A virtual environment is an isolated environment that allows us to install Python packages specific to our project without affecting the global Python installation. Using a virtual environment is very useful for managing project dependencies separately.

To create a virtual environment, run the following command in the terminal or command prompt:

python -m venv myenv

This command will create a folder named myenv containing all the files needed for the virtual environment.

After creating the virtual environment, we need to activate it so that any Python and pip commands we run use this isolated environment.

  • For MacOS/Linux, run the following command:
source myenv/bin/activate
  • For Windows, run the following command:
myenv\Scripts\activate

After activating the virtual environment, you will see the environment name (myenv) appear at the beginning of your terminal prompt, indicating that the virtual environment is active.

(myenv) indicates the virtual environment is active

Installing Django

Once the virtual environment is activated, we can install Django using pip. Django is the web framework we will use to create the To-Do List application.

Run the following command to install Django:

pip install django

Pip will download and install Django along with all necessary dependencies. After the installation is complete, we can verify the Django installation by running the following command:

django-admin --version

This command will display the version of Django that has been installed, for example:

4.2.13

With these steps, we are now ready to start developing a Django application within the isolated virtual environment.

Creating and Running a Django Project

Now we will start by creating our Django project. A Django project is a collection of settings and applications that work together to form a complete web application.

Creating a Django Project

First, we will use the django-admin command to create a new project. Make sure you are in the virtual environment and in the directory where you want to store your project.

django-admin startproject todoproject

This command will create a new directory named todoproject containing the basic structure of a Django project. The directory structure will look like this:

todoproject/
manage.py
todoproject/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
  • manage.py: A utility script that allows us to interact with the Django project, such as running the development server, creating new applications, and performing database migrations.
  • todoproject/: This directory contains the overall project settings. For this project, we don’t need to understand the detailed functions of each file, but we should have a brief idea:
  • __init__.py: An empty file that indicates this directory is a Python package.
  • settings.py: The configuration file for the Django project. Here, we will configure the database, installed applications, middleware, and other settings.
  • urls.py: The file to define URL mappings to various views in our application.

Navigating to the Project Directory

After creating the project, navigate into the project directory using the cd command:

cd todoproject

Now we are in the project directory and ready to run the development server.

Running the Development Server

Django’s development server is a lightweight web server included with Django and used to test our project locally. This server is not for production use but is very useful during development.

Run the following command to start the development server:

python manage.py runserver

After running this command, you will see output similar to this:

Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
June 12, 2024 - 02:23:17
Django version 4.2.13, using settings 'todoproject.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

This means the development server is running, and you can access your Django project in a browser by opening the URL http://127.0.0.1:8000/.

The page above indicates that our Django project has been successfully created and the development server is running properly. Congratulations, we have successfully created and run a Django project. Next, we will create an application within this project and start adding features to our To-Do List application.

Creating Your First Application

After successfully creating a Django project, the next step is to create an application within that project. In Django’s context, an application is a module or component that performs a specific task. A project can consist of one or more applications, depending on the desired complexity and functionality.

Creating a New Application

We will use the startapp command to create a new application. Ensure that we are still in the project directory (todoproject).

manage.py startapp todo

This command will create a new directory named todo within the project directory with the basic structure of a Django application. The directory structure will look like this:

todo/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.py
  • admin.py: A file to register models with the Django admin site.
  • apps.py: The configuration file for the application.
  • migrations/: A directory that stores database migration files for models.
  • models.py: A file to define data models.
  • tests.py: A file to write automated tests for the application.
  • views.py: A file to define views for the application.

Registering the Application in the Project

To ensure that the todo application is recognized by the Django project, we need to add it to the list of installed applications in the INSTALLED_APPS section of the settings.py file. Open todoproject/settings.py and add 'todo', to the INSTALLED_APPS list.

INSTALLED_APPS = [
...
'todo',
]

After adding the application to INSTALLED_APPS, Django will recognize the todo application, and we can start developing functionality for the To-Do List application.

Using Templates

To create a more attractive and dynamic view, Django provides a template mechanism.

Creating a Template

First, we need to create a folder named templates within the todo application directory. Inside the templates folder, create a file named index.html and add the following code:

<!DOCTYPE html>
<html>
<head>
<title>To-Do List</title>
</head>
<body>
<h1>Hello, world. You're at the to-do list index.</h1>
</body>
</html>

In the index.html file above, we write basic HTML to display the message "Hello, world. You're at the to-do list index." inside an <h1> element.

Connecting the Template with the View

After creating the template, the next step is to connect it with the view. We will modify the index view in todo/views.py to use the template we just created.

Open todo/views.py and change the code to the following:

from django.shortcuts import render

def index(request):
return render(request, 'index.html')

In the code above, we use the render function from the django.shortcuts module to render the index.html template. The render function takes two parameters: the request object and the name of the template to be rendered. To check if the template is correctly connected, run the development server again with the following command:

python manage.py runserver

Then open a browser and access http://127.0.0.1:8000/todo/. You should see an HTML page with the message "Hello, world. You're at the to-do list index." displayed inside an <h1> element.

Here we have successfully created a template and connected it with the view. We can enhance this template by adding more HTML elements and creating a more attractive view.

Creating Data Models

In Django, models are used to define the data structure within the application. Django models are responsible for mapping database tables and simplifying database queries. A model is a representation of a table in the database, and each attribute in the model is a column in that table.

To build a data model for the To-Do List application, we need to define the data structure that will be used. This structure includes information such as the title, description, and completion status of each task.

Defining the Model

First, let’s add the Todo model in the models.py file within the todo application:

from django.db import models

class Todo(models.Model):
title = models.CharField(max_length=200)
description = models.TextField()
completed = models.BooleanField(default=False)
def __str__(self):
return self.title
  • title: This field stores the title of the task as text with a maximum length of 200 characters.
  • description: This field stores the task description as text.
  • completed: This field stores the task completion status as a boolean, with the default value set to False.
  • __str__ method: This method is used to provide a string representation of the Todo object, which will display the task title when the object is accessed.

Migrating the Model

After defining the model, we need to create and apply migrations to update the database schema according to the new model. Migrations are Django’s way of applying changes made to the model to the database.

Run the following commands to create and apply migrations:

python manage.py makemigrations
python manage.py migrate
  1. python manage.py makemigrations: This command will check the changes made to the model and create a new migration file based on those changes. This migration file is a representation of the database schema changes that need to be applied.
  2. python manage.py migrate: This command will apply the created migration file to the database. This will update the database tables according to the Todo model definition we just created.

After running these commands, the Todo table will be created in the database with columns corresponding to the attributes defined in the model.

Organizing Models within the Application

Registering the Model in the Admin

Django provides a very useful admin interface to manage application data directly through the web. To manage the Todo model through the admin interface, we need to register the model with the admin site. Add the following code to the admin.py file within the todo application:

from django.contrib import admin
from .models import Todo

admin.site.register(Todo)

By adding admin.site.register(Todo), we inform Django to display the Todo model in the admin site. This allows us to add, edit, and delete To-Do items directly through the admin interface.

Running the Server and Accessing the Admin

After registering the Todo model with the admin site, the next step is to run the Django development server and access the admin interface. If the server is not running, start it with the command python manage.py runserver.

Once the server is running, open a browser and access the admin interface through the URL:

http://127.0.0.1:8000/admin

After reaching the above page, to log in and access the admin page, we need a superuser account. If you don’t have one, you can create it by running the following command in the terminal:

python manage.py createsuperuser

This command will prompt you to enter a username, email, and password for the superuser account. After creating the superuser account, log in to the admin interface using that account.

After logging in, you will see the Todo model in the admin interface. From here, you can manage To-Do items such as adding new items, editing existing items, or deleting unnecessary items. This admin interface is very helpful for managing data during development or after deploying the application.

Adding CRUD Functionality

Creating Forms to Add and Edit To-Do

To add and edit To-Do items, we need forms that users can use. Django provides a simple way to create forms using ModelForm. First, we need to create a forms.py file within the todo application. This file will contain the form definition for the Todo model.

from django import forms
from .models import Todo

class TodoForm(forms.ModelForm):
class Meta:
model = Todo
fields = ['title', 'description', 'completed']
  • Import Django Forms: We import the forms module from Django.
  • Import Todo Model: We also import the Todo model that we created earlier.
  • Defining TodoForm Class: We create a TodoForm class that is a subclass of forms.ModelForm.
  • Meta Class: Inside the TodoForm class, we define a Meta class. This class is used to inform Django which model to use for creating the form and which fields to include in the form.

Using ModelForm, we can easily create and edit To-Do items, as Django will automatically generate the form based on the Todo model and the fields we have specified. This form will allow users to enter the title, description, and completion status of each To-Do item.

Adding Views to Add and Edit To-Dos

So far, we have interacted with models.py, views.py, and forms.py. In web development using Django, we often need to interact with the database through models, collect data from users through forms, and display that data through views. As a reminder, models.py is used to define the data structure of your application. This model maps to database tables and provides an interface to query the database. Then forms.py is used to define forms for collecting data from users. Finally, views.py is used to handle the logic of your application and interact with models and forms. Views send data to templates, which then display it to the user.

Previously, we only displayed a simple “Hello, world” message in the view. Now it’s time to set up views to create and edit to-do items. In the views.py file within the todo application, we will add the following:

from django.shortcuts import render, redirect
from .models import Todo
from .forms import TodoForm

def todo_list(request):
todos = Todo.objects.all()
return render(request, 'todo_list.html', {'todos': todos})

def todo_detail(request, pk):
todo = Todo.objects.get(pk=pk)
return render(request, 'todo_detail.html', {'todo': todo})

def todo_create(request):
if request.method == 'POST':
form = TodoForm(request.POST)
if form.is_valid():
form.save()
return redirect('todo_list')
else:
form = TodoForm()
return render(request, 'todo_form.html', {'form': form})

def todo_update(request, pk):
todo = Todo.objects.get(pk=pk)
if request.method == 'POST':
form = TodoForm(request.POST, instance=todo)
if form.is_valid():
form.save()
return redirect('todo_list')
else:
form = TodoForm(instance=todo)
return render(request, 'todo_form.html', {'form': form})

def todo_delete(request, pk):
todo = Todo.objects.get(pk=pk)
if request.method == 'POST':
todo.delete()
return redirect('todo_list')
return render(request, 'todo_confirm_delete.html', {'todo': todo})
  • todo_list: This view retrieves all To-Do items from the database and renders them to the todo_list.html template. This view is used to display a list of all To-Do items.
  • todo_detail: This view retrieves the details of a single To-Do item based on its primary key (pk) and renders them to the todo_detail.html template. This view is used to display the details of a single To-Do item.
  • todo_create: This view is used to create a new To-Do item. If the request method is POST, the form data will be validated and saved to the database. If valid, the user will be redirected back to the To-Do list. If the request method is not POST, an empty form will be rendered in the todo_form.html template.
  • todo_update: This view is used to edit an existing To-Do item. Similar to todo_create, but here the form is pre-filled with the data of the item to be edited. If the request method is POST and the form is valid, the changes will be saved to the database and the user will be redirected back to the To-Do list.
  • todo_delete: This view is used to delete a To-Do item. If the request method is POST, the To-Do item will be deleted from the database and the user will be redirected back to the To-Do list. If not POST, the user will be asked for confirmation in the todo_confirm_delete.html template.

By adding these views, our application now has CRUD (Create, Read, Update, Delete) functionality for To-Do items. These views allow users to add, view, edit, and delete To-Do items through the web interface.

Mapping URLs to CRUD Views

To connect the views we have created with URLs, we need to add URL patterns in the urls.py file within the todo application. This allows the Django application to map the URLs requested by the user to the appropriate views. Open or create the urls.py file within the todo application (todo/urls.py). Add the following URL patterns to map the CRUD views:

from django.urls import path
from . import views

urlpatterns = [
path('', views.todo_list, name='todo_list'),
path('todo/<int:pk>/', views.todo_detail, name='todo_detail'),
path('todo/new/', views.todo_create, name='todo_create'),
path('todo/<int:pk>/edit/', views.todo_update, name='todo_update'),
path('todo/<int:pk>/delete/', views.todo_delete, name='todo_delete'),
]
  • path(‘’, views.todo_list, name=’todo_list’): This URL maps the root URL (/) to the todo_list view. This will display a list of all To-Do items.
  • path(‘todo/int:pk/’, views.todo_detail, name=’todo_detail’): This URL maps URLs like /todo/1/ to the todo_detail view. <int:pk> is a parameter that captures the primary key of the To-Do item to be displayed.
  • path(‘todo/new/’, views.todo_create, name=’todo_create’): This URL maps the URL /todo/new/ to the todo_create view. This will display a form to add a new To-Do item.
  • path(‘todo/int:pk/edit/’, views.todo_update, name=’todo_update’): This URL maps URLs like /todo/1/edit/ to the todo_update view. <int:pk> is a parameter that captures the primary key of the To-Do item to be edited.
  • path(‘todo/int:pk/delete/’, views.todo_delete, name=’todo_delete’): This URL maps URLs like /todo/1/delete/ to the todo_delete view. <int:pk> is a parameter that captures the primary key of the To-Do item to be deleted.

After adding the URL patterns in urls.py within the todo application, we need to connect this application's URLs to the main Django project. To do this, add the todo application's path to the project's urls.py. Open urls.py within the todoproject directory. Add the todo application's path using include.

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
path('admin/', admin.site.urls),
path('', include('todo.urls')),
]

With this configuration, the root URL (/) will be mapped directly to the URL patterns defined in urls.py within the todo application.

Creating Templates for the Interface

To create a complete user interface for the To-Do application with full CRUD functionality, we need several HTML templates. These templates will be linked to the views we created earlier.

Main Page Template for To-Do List (todo_list.html):

<!DOCTYPE html>
<html>
<head>
<title>To-Do List</title>
</head>
<body>
<h1>To-Do List</h1>
<a href="{% url 'todo_create' %}">Add new task</a>
<ul>
{% for todo in todos %}
<li>
<p><a href="{% url 'todo_detail' todo.pk %}">{{ todo.title }}</a><span>: {{ todo.completed|yesno:"Completed,Not Completed" }}</span>
<a href="{% url 'todo_update' todo.pk %}">Edit</a>
<a href="{% url 'todo_delete' todo.pk %}">Delete</a></p>
</li>
{% endfor %}
</ul>
</body>
</html>

This todo_list.html template will display a list of all To-Do items. There are links to add a new task, view task details, edit tasks, and delete tasks. The {% for todo in todos %} loop is used to display each To-Do item in the list.

Template for To-Do Detail (todo_detail.html):

<!DOCTYPE html>
<html>
<head>
<title>To-Do Detail</title>
</head>
<body>
<h1>{{ todo.title }}</h1>
<p>{{ todo.description }}</p>
<p>Status: {{ todo.completed|yesno:"Completed,Not Completed" }}</p>
<a href="{% url 'todo_list' %}">Back to list</a>
</body>
</html>

This todo_detail.html template displays the details of a single To-Do item. It uses the variables {{ todo.title }}, {{ todo.description }}, and {{ todo.completed|yesno:"Completed,Not Completed" }} to display relevant information about the task.

Template for To-Do Form (todo_form.html):

<!DOCTYPE html>
<html>
<head>
<title>To-Do Form</title>
</head>
<body>
<h1>To-Do Form</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Save</button>
</form>
<a href="{% url 'todo_list' %}">Cancel</a>
</body>
</html>

This todo_form.html template is used to display a form that allows users to add or edit To-Do items. The form uses {{ form.as_p }} to automatically generate form elements based on the TodoForm we created. The CSRF token ({% csrf_token %}) is required for form security in Django.

Template for Delete Confirmation (todo_confirm_delete.html):

<!DOCTYPE html>
<html>
<head>
<title>Delete To-Do</title>
</head>
<body>
<h1>Are you sure you want to delete "{{ todo.title }}"?</h1>
<form method="post">
{% csrf_token %}
<button type="submit">Yes, delete</button>
</form>
<a href="{% url 'todo_list' %}">Cancel</a>
</body>
</html>

This todo_confirm_delete.html template is used to ask for confirmation from the user before deleting a To-Do item. It displays a confirmation message with the title of the task to be deleted and provides buttons to confirm or cancel the deletion.

With these four templates, your To-Do application now has a complete user interface for performing CRUD operations. Make sure all these templates are saved in the templates folder within the todo application.

Conclusion

In this article, we have learned how to create a simple To-Do List application using Django, a popular web framework for the Python programming language. We have gone through various steps, from installing Django to creating and running the project, building data models, writing views, mapping URLs, and creating HTML templates to support CRUD operations (Create, Read, Update, Delete). Here are the key points we have covered:

  • Installation and Environment Setup: Creating a virtual environment and installing Django.
  • Creating a Django Project: Using django-admin to create a Django project and running the development server.
  • Creating a Django Application: Using startapp to create a new application within the Django project.
  • Writing Views and Mapping URLs: Creating simple views and mapping URLs to those views.
  • Using Templates: Creating HTML templates and linking them to views to display data.
  • Building Data Models: Defining and migrating data models for the To-Do List application.
  • Registering Models in Admin: Registering models with the Django admin site to facilitate data management.
  • Adding CRUD Functionality: Creating forms to add and edit To-Do items, writing views and templates to support CRUD operations.

There are many additional features you can develop from this basic To-Do application. Here are some suggestions for further learning and enhancement:

  • User Interface: Improve the user interface by using CSS frameworks like Bootstrap or Tailwind CSS to make it more attractive and responsive.
  • Form Validation: Add more complex form validation to ensure the data entered by users meets the expected criteria.
  • Authentication and Authorization: Implement user login and registration features to restrict access to the application to registered users only. Django has built-in support for authentication.
  • Additional Features: Develop additional features like task categories, due dates, task priorities, and notifications.

The most important thing is to always be willing to learn and open to new things. Happy coding! 😁

Source Code: Github

Support me here 😊

--

--

Muhammad Ihsan
CodeX
Writer for

Computer Vision Enthusiast, Freelance AI Engineer. Posting about Programming and Philosophy. https://emhaihsan.hashnode.dev/ for articles in Bahasa Indonesia