Building a task management app with Anvil

Anvil is a powerful and versatile tool for building full-stack web applications. With Anvil, you can quickly and easily create your UI and write Python code to control the front-end and back-end of your app. Creating apps with Anvil is fast and flexible, making it well-suited for building internal tools. This simple but powerful task management app demonstrates some of what you can do with Anvil.

Opening and editing a project in the task management app

I built the app’s UI with Anvil’s drag-and-drop editor and by writing front-end Python code. The back-end is also written in Python code in a secure Server Module. The app also uses Anvil’s built-in database system and user management service. Keep reading to learn more about how I built the task manager app with Python and Anvil.

What it does

The app is a simple task manager that allows you to create and manage projects. Each project is a configurable table of tasks where users can give tasks a priority level, add checkboxes and assign other users to tasks. The table of tasks is displayed using a Data Grid. Users can click on the cells in the table to edit their contents.

Creating a new project and adding a column.

Creating a new project and adding a column.

On the main page, there is a board view of all the projects. Here, you can add comments to or delete projects.

Adding a comment and deleting a project

Adding a comment and deleting a project

How it’s built

Building the database

Every Anvil app comes with a built-in database system built on top of PostgreSQL. Anvil’s Data Tables have a GUI for creating, editing and deleting tables, but tables can also be edited via Python code. To build my task manager app, I first needed to define my database schema.

I needed a way to store the columns in each user-created project table and the data in each row. I did this by first creating a table to store the name and type of all the columns in the projects.

Screenshot of the Columns Data Table showing two columns: title and type

The Columns Data Table stores the title and type of all columns in all projects

Next, I created a table to store all the projects. This table has a column for the project name and a column that links to columns table. This connects each row in the Columns Data Table with its corresponding project.

Screenshot of the Projects Data Table showing two columns:project_name and columns

The Projects Data Table stores the name of each project and links to the
Columns Data Table

Finally, a third Data Table stores the data for each row in all the projects. This table has a column linking back to Projects Data Table and a column for the row data, stored in a simple dictionary.

Screenshot of the Rows Data Table showing two columns: project and data

The Rows Data Table links to a row from the Projects table and stores the
data for each row in all the projects

Writing back-end Python

Anvil’s Server Modules are a full server-side Python environment. Server Modules cannot be edited or seen by the user, so we can trust them to do what we tell them. By default, the Data Tables in an Anvil app are not editable by users, but they can be accessed from a Server Module. In the task manager app, any updates to the Data Tables occur in server-side functions within a Server Module. These functions can be called from client-side Forms using just one line of code.

For example, when a new column is added to a Data Grid, a new row is added to the Columns Data Table and that new row is then linked to the project in the Projects Data Table.

@anvil.server.callable
def add_column_to_db(column_name, project, type):
    #project is a row from the Projects Data Table
    #add a new row to the Columns Data Table
    column_row = app_tables.columns.add_row(title=column_name, type=type)
    #link the new column to Projects
    project['columns'] += [column_row]
    return column_row

The @anvil.server.callable decorator means that this function can easily be called from client-side code:

anvil.server.call('add_column_to_db', title, self.project, type)

Creating the UI with client-side Python

I created the app’s UI by using both Anvil’s drag-and-drop UI builder and by writing Python code to dynamically generate UI elements. For example, to create the project view page of my app, I dragged a Data Grid onto the page which is then used to display the table of tasks for each project:

Dragging-and-dropping a Data Grid from the Toolbox onto the ProjectView Form

Dragging-and-dropping a Data Grid from the Toolbox onto the ProjectView Form

The drag-and-drop designer makes building the front-end of your app a breeze, but sometimes you’ll want to build the front-end in code instead. For example, in the left navigation menu of my task management app, there are Links to all the projects in the app.

Adding a new project from the left navigation menu then renaming it.
The links in the menu are cleared and regenerated when the project is renamed

Adding a new project from the left navigation menu then renaming it.
The links in the menu are cleared and regenerated when the project is renamed

These Links are dynamically generated via code and updated anytime a project is created, deleted or renamed. Below is the Python function that searches the database for projects and creates Links for each project. The function is written in a client-side Form that runs in the user’s browser.

def add_project_links(self):
    #clear out the container that the links are in
    self.link_panel.clear()
    #get a list of the projects from the database
    for row in anvil.server.call('get_projects'):
      #create a link
      link = Link(text=row["project_name"], tag=row)
      #set up a event handler that opens the project when the link is clicked
      link.set_event_handler("click", self.open_project)
      #add the link to the container
      self.link_panel.add_component(link)

Anvil has many pre-built components that you can add to your apps, but you can also create your own component types using Custom Components. In my task manager app, I created a Custom Component that allows users to edit the text of the component by clicking on it. I reused this Custom Component throughout the app to make the contents of the project tables and the name of the projects user-editable.

Clicking on the Custom Component allows the text to be edited.
Pressing enter saves the new text.

Clicking on the Custom Component allows the text to be edited.
Pressing enter saves the new text.

Adding the User Management Service

Anvil also provides built-in user management that handles signup, login and user permissions. I added the Users service to my task management app so that team members can log in and work on projects together. Adding the Users service to an Anvil app automatically creates a Users table where you can manage access to your app. Since the Users table is an ordinary Data Table, I also used it to create a component for assigning tasks to users.

Recording of clicking on a cell in a Data Grid and choosing a user's email address from a Drop Down to select the user.

Assigning a task to a user

Anvil handles the login process, including single-sign-on with Google, Microsoft or your corporate SAML provider. I just needed to add anvil.users.login_with_form() to my app so that users are presented with a login form on startup.

Screenshot of the login form.

What next?

Clone the app to check out the source code and try it for yourself!

If you’re new to Anvil, why not try a 5-minute tutorial to learn more about building web apps with nothing but Python? Or if you’re an experienced Anvil user, why not extend the app? Here is some inspiration for features to add:

  • Make the board view more informative. Try displaying the number of tasks in each project on the card.
  • Add deadlines. Use a Date Picker component to allow users to set a deadline on a project. If the deadline has passed, make the colour of the deadline red. Expand this even further by adding a new type of column to project tables that lets you set a date for each task.
  • Archive tasks. Add a function that lets users archive tasks without deleting them. They shouldn’t show up in the normal table but still be viewable somehow.
  • Allow multiple tables per project. Right now, the app only allows one table per project. Allow users to add or delete tables to a project. Think about how this would change your database structure.

Show us what you’ve built! Have you created a cool internal tool with Anvil or extended this Task Manager app? Let us know! We’d love to see what you’ve built on our Show and Tell Community Forum.


Want to dig into how this app works? Our tutorials show you all the pieces this app is made from, and more: