Storing feedback in a database

In this tutorial, we’ll take a tour of Anvil and build a simple feedback form. We’ll start from a blank page, and build up to a web app with database storage, email functionality and deployed on the web - all in nothing but Python.

The final app will look something like this:

The techniques you’ll learn in this tutorial are fundamental to building any Anvil app, and mastering them will give you a good understanding of how Anvil works.

In this tutorial, you’ll learn how to:

  1. Build your user interface
  2. Create your database table
  3. Write server-side Python
  4. Write client-side Python
  5. Send emails

Click the following link to clone the finished app and explore it yourself, or read on as we take a step-by-step guide to building it yourself.

You don't need any prior experience with Anvil or web development to complete this tutorial.

All you'll need is a little bit of Python. If you’re new to Python, here are some resources to help you get started.

Chapter 1

Build your user interface

Let’s start by building your UI using Anvil’s drag-and-drop editor.

Create an app

Log in to Anvil and click ‘New Blank App’. Choose the Material Design theme.

Location of the Create App button

First, name the app. Click on the name at the top of the screen and give it a name.

Add components

We construct the UI by dragging-and-dropping components from the Toolbox into the page.

The Theme Elements part of the Toolbox contains components that are specific to the current app’s Theme. Here, you’ll find the Card component:

Location of the Card component in the Toolbox

Drop a Card Card icon, and a Label Label icon into the page.

Anvil Design View with a UI consisting of a Card and a Label

Change component properties

Below the Toolbox, you’ll see the Properties Panel, where you edit the styling and behaviour of your components by changing their properties.

Select the Label you just added to the page, and change the text to ‘Feedback Form’.

Location of the 'text' property in the Properties Panel

Next, change the role to Headline.

Changing the 'role' property in the Properties Panel

Our feedback form will ask our users for their name, email address, and to leave some feedback.

We’ll use Labels for our input prompts. Drop three Labels Label icon into the page, and change their text properties to:

  • Name:
  • Email:
  • Feedback:
Dropping three Labels onto the page

Drop two TextBoxes TextBox icon and a TextArea TextArea icon into the page for our user inputs, and rename them name_box, email_box and feedback_box.

Dropping two TextBoxes and a TextArea onto the page

We’re changing the name of each user input component, to make it easier to identify them from code.

Finally, Drop a Button Button icon into the page. In the Properties Panel:

  • Change the name from ‘button_1’ to ‘submit_button’
  • Change the text from ‘button_1’ to ‘Submit’
  • Change the role to ‘primary-color’.
Adding a Button, and changing the text, role, and name using the Properties Panel

Our UI is now complete. Nice job! Time for Chapter 2.

Chapter 2

Create your database table

We’ll use Data Tables to store feedback from our users. Data Tables are an out-of-the-box option for data storage in Anvil, and they’re backed by PostgreSQL.

In the panel on the left (the App Browser), click the ‘+’ next to ‘Services’, then click on Data Tables.

Location of the 'Add a service' button


Now set up your “feedback” table, with the following columns:

  • name (Text column)
  • email (Text column)
  • feedback (Text column)
  • created (Date and Time column)
Creating a Data Table with 'name', 'email', 'feedback' and 'created' columns
  1. Click ‘Add a table’ in the light blue box at the top, then ‘Create new table…’. You’ll be prompted to give your table a name - let’s call it ‘feedback’.

  2. Next, add a column for the name of the person submitting feedback, by clicking ‘+ New Column’ and choosing ‘Add text column…’. Call this column ‘name’.

  3. Keep adding columns until your Data Table has the structure we described above. Column titles are case sensitive, so let’s stick to lower case.

Your Data Table should look something like this:

Data Table with 'name', 'email', 'feedback' and 'created' columns

Your Data Table is set up and ready to use. Nice work! Time for Chapter 3.

Chapter 3

Write server-side 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. This is why we’ll use a Server Module to write to the Data Table.

Create a Server Module by clicking the ‘+’ next to Server Modules in the App Browser. You’ll see some code with a yellow background:

Adding a Server Module

We’ll write a server function to add a new row to the ‘feedback’ Data Table we just created. We’ll use the add_row method to do this.

Add this function to your Server Module:

def add_feedback(name, email, feedback):

The @anvil.server.callable decorator allows us to call this function from client code.

We’re using the datetime library to set the ‘created’ column to the current date and time, so you’ll also need to import the datetime class at the top of your Server Module:

from datetime import datetime

Great! We now have a server function that will add a new row to our Data Table when it’s called. Let’s go ahead and link it up with our UI. On to Chapter 4!

Chapter 4

Write client-side Python

We want to store information in our Data Table when users click the ‘Submit’ button. This means calling the add_feedback server function when our users click the submit_feedback Button.

We’ll use Events for this.

Set up an event handler

Anvil components can raise events. For example, when a Button is clicked, it raises the ‘click’ event.

Click on ‘Form1’ in the App Browser to go back to your UI. Click on your ‘Submit’ Button, and scroll to the bottom of the Properties Panel. You’ll see a list of events for the Button.

Click the blue arrows next to ‘click’.

Configuring a click event handler for a Button using the Properties Panel

You will be taken to the Form Editor’s ‘Code’ view.

This is where you write your client-side Python code that runs in the browser.

You’ll see a submit_button_click method on your Form that looks like this:

def submit_button_click(self, **event_args):
  """This method is called when the button is clicked"""

This is the Python method that runs when the ‘Add an article’ Button is clicked.

For example, to display a simple popup with the text ‘You clicked the button’, you would edit our submit_button_click function as follows:

def submit_button_click(self, **event_args):
  # Display a popup that says 'You clicked the button'
  alert("You clicked the button")

Run your app

To see it in action, click the ‘Run’ button at the top of the screen:

Location of the 'Run' button

Click the Submit button and your popup should appear!

Capture user inputs

When someone clicks Submit on our feedback form, we want to store a name, email address, and some feedback for that person in our Data Table.

We can read data from our input components by reading their properties. For example, we can read the text in our TextBoxes using their text property.

Edit your submit_button_click function to look like this:

def submit_button_click(self, **event_args):
  # Set 'name' to the text in the 'name_box'
  name = self.name_box.text
  # Set 'email' to the text in the 'email_box'
  email = self.email_box.text
  # Set 'feedback' to the text in the 'feedback_box'
  feedback = self.feedback_box.text

Great! Now we’ve captured the name, email, and feedback that we want to store in our Data Table.

We want to call our add_feedback server function when the button is clicked, and pass in the user inputs. We made our add_feedback server function available to our client-side code by decorating it as @anvil.server.callable.

This means we can call it from our client-side code using'add_feedback', <arguments>)

Let’s call our add_feedback server function from our submit_button_click function:

def submit_button_click(self, **event_args):
  name = self.name_box.text
  email = self.email_box.text
  feedback = self.feedback_box.text
  # Call your 'add_feedback' server function
  # pass in name, email and feedback as arguments'add_feedback', name, email, feedback)

Display a notification

We’ll also display a temporary popup using a Notification to let our users know their feedback has been submitted.

Edit your submit_button_click function to look like this:

def submit_button_click(self, **event_args):
  name = self.name_box.text
  email = self.email_box.text
  feedback = self.feedback_box.text'add_feedback', name, email, feedback)
  # Show a popup that says 'Feedback submitted!'
  Notification("Feedback submitted!").show()

Clear our user inputs

There’s one final step left, and that’s to clear our user inputs each time someone submits feedback.

We’ll do this in a separate function to keep our code nice and clean.

Add this method to your Form, underneath your submit_button_click() method:

def clear_inputs(self):
  # Clear the 'name_box'
  self.name_box.text = ""
  # Clear the 'email_box'
  self.email_box.text = ""
  # Clear the 'feedback_box'
  self.feedback_box.text = ""

Finally, let’s call this from our submit_button_click method, so that we clear our inputs each time feedback is submitted.

Edit your submit_button_click function to look like this:

def submit_button_click(self, **event_args):
  name = self.name_box.text
  email = self.email_box.text
  feedback = self.feedback_box.text'add_feedback', name, email, feedback)
  Notification("Feedback submitted!").show()
  # Call your 'clear_inputs' method to clear the boxes

Run your app

Time to Run your app! Click the ‘Run’ button at the top of the screen, fill in a name, email address, and some feedback and click Submit.

Then, stop your app, and go to your Data Tables. You’ll see you have a new row of feedback in your Data Table!

Running the app, completing the inputs and clicking Submit, stopping the app and seeing the data stored in the Data Table

Chapter 5

Send emails

We’ll use the Email Service to send you an email each time someone leaves feedback.

Add the Email Service

Add a new Service, the same way you added the Data Tables service, and select ‘Email’:

Adding a service
Adding the Email Service

Now you’ve enabled the Email Service, it’s just one line of Python to send an email.

Go to your Server Module, and modify your add_feedback function to look like this. Remember to change the address to your email address!

def add_feedback(name, email, feedback):
  # Send yourself an email each time feedback is submitted"", # Change this to your email address!
                   subject="Feedback from {}".format(name),
  A new person has filled out the feedback form!

  Name: {}
  Email address: {}
  """.format(name, email, feedback))

Run your app

Let’s run your app again! Click the ‘Run’ button at the top of the screen, fill in a name, email address, and some feedback and click Submit.

When you click Submit, you’ll receive an email letting you know someone has filled out your feedback form.

That’s it!

And that’s it. You’ve just built a working database-backed feedback app with built-in email functionality in Anvil.

Your app is already live on the internet. Go to Publish App in the Gear Menu gear icon for details.

You can also use the following link to clone the finished app and explore it yourself:


Congratulations! You’ve built and shipped a database-backed web application!

You also now have a solid foundation in Anvil.

What next?

Head to the Anvil Learning Centre for more tutorials, or head to our examples page to learn how to build more complex apps in Anvil.