Create Your First Django App (todo app case study)
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.
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 toFalse
.__str__
method: This method is used to provide a string representation of theTodo
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
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.python manage.py migrate
: This command will apply the created migration file to the database. This will update the database tables according to theTodo
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 offorms.ModelForm
. - Meta Class: Inside the
TodoForm
class, we define aMeta
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 thetodo_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 thetodo_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 thetodo_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 thetodo_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 thetodo_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