Todo App With Django And Bulma

Django and Bulma

Django is a fantastic technology that has proven itself as a solid and reliable Python Web Development Framework. Bulma is a new and really cool CSS Framework for making your front end look as good as it can. In this tutorial, we will use Django on the back end with Bulma CSS on the front end to build a small Todo application. We’ll see how to add items to a list, style them accordingly, mark items as complete or incomplete, as well as a few other tricks. Let’s get started with a Todo application in Django and Bulma now.

Getting Started

This tutorial assumes you have Python and Django installed and running, ready to start building your application. If you need help getting those aspects ready to go, Django For Beginners might be a good first read.

Start A New Django Project

We can begin by starting a new Django project using the command startproject todo.

(vdjango) vdjango $ startproject todo

Then, we’ll quickly start up the Django server using python runserver just to confirm everything is working, and things look good!

(vdjango) todo $python runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 17 unapplied migration(s). Your project may not work properly until you
apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python migrate' to apply them.
May 18, 2020 - 09:49:58
Django version 3.0.6, using settings 'todo.settings'
Starting development server at
Quit the server with CTRL-BREAK.

django installed successfully

With the Django project scaffolded out, we can cd into the project directory and run the built-in migrations using python migrate.

(vdjango) vdjango $cd todo
(vdjango) todo $python migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying sessions.0001_initial... OK
(vdjango) todo $

Visiting The Admin Dashboard

Django has a great administrative dashboard that you get for free. We can check it out by visiting in the web browser of your choice.

django built in admin login

Now to make use of this admin area, we need a superuser to do so. We can easily create one with the python createsuperuser command.

(vdjango) todo $python createsuperuser
Username (leave blank to use 'compname'): admin
Email address:
Password (again):
Superuser created successfully.
(vdjango) todo $

django superuser admin login

Use the credentials you provided when creating your superuser to log in to the admin area and have a look around.

django admin logged in

Start Your App

Django is designed so that you can create reusable applications. There are many great Django Packages available you can plug and play right into your Django project. A Django project is just a collection of one or many apps. Let’s create a new app now with the command python startapp todoapp.

(vdjango) todo $python startapp todoapp

Once that command runs, you’ll see a new directory in your Django project that holds all of the files needed for the app.

django startapp files

Register Your App

When you add a new app to your Django project, you need to let Django know about it. This can be done in the file like we see here. We can add the todoapp like so:

Adding a file for your app

Each app needs a file to route HTTP traffic properly in your Django project. We can add that file manually now.

django add urlspy to app

To get started with creating URL mappings, import the path module from django.urls.

Using include() with urls

In the project-level directory (not our new app!), we want to set things up so that when a user visits the root URL, our Django project will point this request to the new app we just created. What the code below does is essentially take all incoming requests, and forwards them to the file that lives in the todoapp directory.

Adding Templates

To display a web page to the user, Django makes use of templates. Let’s add a home page template to the application. The convention is to create a template directory, and then another directory inside that one using the name of the app.

django templates in app

We’ll put just an HTML snippet like so.


Using View functions in

In the file for the app, we want to import the views module and call a function when someone requests the home page. In this code, the home() function of the file will be called, and it is a named route of home. In Django, you always want to name your routes so that you can set up dynamic links.

Now we can add the code needed in the file to handle the request.

If everything goes according to plan, you should see a simple HTML page like this when you visit the site.

first web page django

Adding Bulma CSS in a Base template

Now we want to accomplish two goals. One is to make our little project look stylish, and the other to reduce code repetition. We can do this by creating a base template to extend from while including the Bulma CSS library in that base template.

django base_html file


Extend From Base

We can update the home.html template to extend from the base.html file we just created.


Right away, we can see the font has updated and already looks better!

base template extends django

Adding A Navbar

Bulma has a nice looking navigation bar you can implement quite easily. We can put the markup for the navbar in the base.html file. That way, any template file that extends from the base will automatically have the navbar included.


There we go! The navbar is looking nice even in the beginning stages.

bulma in django base template

Dynamic Data With Django Models

More fun can be had as we get into working with Models in Django. Models hold all of the data for the application. We can open up the file from our application, and add the code seen here.

Anytime you create a new Model or edit an existing model in Django, you *must* create a new migration. By running python makemigrations, Django will scan those files, and build migration files automatically for you. These migration files are used to modify the database to hold data meeting the requirements of the application.

(vdjango) todo $python makemigrations
Migrations for 'todoapp':
    - Create model Todo
(vdjango) todo $

For example, the migration below is what was created in this case.

python managepy makemigrations

Migrate The Database

In order for those migration files to work, you need to migrate the database. That can be done by running python migrate.

(vdjango) todo $python migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, todoapp
Running migrations:
  Applying todoapp.0001_initial... OK
(vdjango) todo $

So the takeaway is that when working with Models you always:

  • 1. Create The Model (or edit)
  • 2. Create The Migrations
  • 3. Run The Migrations

Add Your Models To Admin

Not only does Django create the Model and Migrations for you, but it also gives you a way to register that Model with the Admin Dashboard. Once it is registered in the admin dashboard, you automatically get full CRUD (Create, Read, Update, Delete) ability right in the admin area.

Just like that, the Todoapp and Todo model is visible in the Admin dashboard.

register model in django admin

Let’s add a new record to the database using this Model.

add items to django admin

Cool! It is added with a nice success message.

view new items in django admin

Go ahead and add a few items so that we have some data to work with in the next section.

Working With Function-Based Views

Django has something known as Class Based Views, but in this example, we will use the easier to understand Function-Based Views. In the code below, the first thing we need to do is to import the Todo model we created earlier. With that in place, we define a home function that uses the Django ORM to fetch all todos from the database. Once we have them, we render the home template while also passing the data to that template using the context dictionary.

Looping Over Items In A Template

This gives us access to all of those todos we just fetched from the database. We can loop over them and output information about each todo like so.


Things are taking shape! We now see all of the records from the database getting output to the home page.

updated django home page

Using A Table In Bulma

To spruce things up a bit, we’ll make use of a nice table layout for the todo items using an HTML table styled with Bulma CSS. We can add headers to each column so it is a bit more clear as to what the data is. We have the task to be completed, whether it is completed or not, and the beginnings of a link to delete the todo.


bulma css table

Conditional Logic In Templates

We can take various actions in the template based on what the data holds that we are looping over. The code below adds the ability to display a line-through and checkmark on completed items. For incomplete items, we display the normal text along with an empty circle. The icons are made available via Font Awesome. Bulma and Font Awesome kind of work like bread and butter.


This provides for a pretty cool effect!

bulma font awesome checkmark

Using Django Forms

Let’s get our form working properly in this Django app. To do so, we need to add a file to the application directory.

add formspy to django app

This example here makes use of Django Model Forms. These things are incredible and feel like magic once you get them working :-).

This new Model Form can now be imported in our file. The new TodoForm class uses an object instance to hold any data sent from the HTML form. To populate the form in code, all you need to do is use form = TodoForm(request.POST or None). By reading the other code, you can see how to validate the form, and save it to the database. Note that in Django, a particular view function can handle either a GET or POST request. It is your responsibility to check for what the request type is, then take the appropriate action.

The form that exists in the base.html file needs to be updated to work with our model. The snippet below shows how we set the method to POST, add a csrf token, and ensure that the properties of the input tag are correct.


Test Out The Form

We are ready to type a new todo item into the form, then click submit. This should add the todo item and save it to the database.

django form submit

After clicking on submit, the page reloads with the new todo item added to the table. The form is working!

the django form submit worked

Adding Flash Messages

Django has a nice messages module that makes it easy to add flash messages to your application. First, we can update the code in the views file to make use of the messages module.

In the template, we can check for the presence of a flash message and if one is present, output the message using the Bulma CSS styling for a nice effect.


Let’s add another task to our list of todos.

add another todo django

Bingo! Now the todo is added, but we also get a nice message that it was added successfully.

django success flash message

Delete An Item By Id

In this section, we can set up the routing, view, and link in the template file to allow for deleting a specific todo task.


Now we click one of the links for a specific task, in this case, we click the link for “Wash The Lettuce” to delete that todo.

add link for delete django item

Just like that, that particular task is deleted.

django delete by id

Mark A Todo As Complete or Incomplete

We also want the ability to mark a task as complete or incomplete. Maybe we don’t want to delete the task entirely but have a running list where you can cross off completed items. We can set that up now.


Check out the short video clip below to show this in action now.

Edit A Task

The last piece of functionality we can add is the ability to edit a todo item. The goal is to provide a link for each task description, which then launches a prepopulated form with the data to edit. Then, the user can make any edits they like, click the submit button on the form, and the task will have been updated. Once again, below are the edits to the URLs, views, and templates to get this wired up.


Now, we test this out by clicking on the ‘Edit Task’ link for the “Pick Some Tomatoes” todo item. It loads up a new form with that text, and we change it to “Pick So Many Tomatoes!!”. Once the button is clicked, the edit is complete and the page redirects with a nice flash message to let us know the edit was successful.

Todo App With Django And Bulma Summary

Thanks for reading this fun little tutorial about using Django and Bulma together to build a basic todo application. We saw how to do all of the CRUD operations in Django, along with learning a bit about the cool new CSS framework Bulma.