Day 9 of the Anvil Advent Calendar

Build a web app every day until Christmas, with nothing but Python!

Manage your Christmas card list

We’ve built an app to send a Christmas card from the web, and that’s all very nice. But you have to type in everything, every time. What we really want is to build our Christmas card list in a database, and send all our cards at once.

So, of course, we built an app to do it. Here’s how it looks:

See the source code

You can open the app’s code here:

If you’re reading through the rest of this guide, it will be helpful to have the code handy:

How it works

This sort of app is typically known as CRUD (don’t worry, I won’t tell the people you’re sending cards to). It’s a common pattern: you’ve got a list of items (in this case colleagues, family members, pets, etc), and you need to Create new ones, Read or Update existing ones, or Delete them.

Anvil makes this pretty easy. First, there’s a Data Table of contacts, with a column for each of the address fields Handwrytten needs, plus a flag to say whether we’re sending them a card this year (so you can still keep track of that one aunt):

The Home form lists all your contacts, using a Data Grid.

Within each item, you can click on a name to edit it, or on a trash-can icon to delete it. Editing a contact opens the EditContact form, which lets you add or change anything you need about the contact.

To save on coding, those text boxes are linked to the data using Data Bindings – but if you look at the source code, you can see that they’re not editing the database row directly. Instead, we create a buffer: a dict object that starts with all the same content as the row. That way, if the user clicks Cancel, we can just throw their edits away. If they click Save, we send the dict to a server-side function (update_contact()) to update the database row.

This gives you the Reads and Updates; let’s handle Creation and Deletion.

Creation is pretty easy: We open the EditContact form without a database row. We edit the buffer dictionary, and when we hit Save, we get update_contact() to create a new row for us.

Deletion is a little trickier. We do this from the list on the Home form, with a “delete” icon on the item template for each row in the list. When you click the “Delete” link, we raise an event on the RepeatingPanel, which triggers the top-level Home form to delete the contact and then refresh the list.

A search box is a great way to navigate. On the Home form, the function that fetches your contacts sends the contents of the search box to the server, and we use the ilike query operator to search for matching names.

We automatically refresh the data when you press Enter in the search box, but we also want to search as you type. So we use a Timer component: every time you press a key, we set the timer for 0.5 seconds. If you stop typing for half a second, it will raise a “tick” event, which will cause us to refresh the page with your latest search query.

Sending the cards

Of course, the point of the whole affair is to send cards to these people! (For more on that, check out our original article on sending real cards with Python.) So we have a big Send cards button. When clicked, we open a compose window to write a message for our cards:

This dialog box is another form (SendDialog), used as the body of an alert. We have configured the alert with custom buttons: If the user clicks the Send button, the alert() function returns True, and we send the cards.

The card-sending code is more or less the same as last time – but, because we might be sending a lot of cards, this time we launch a Background Task so the UI doesn’t have to wait.

That source code again

That concludes our tour of a simple address-book manager app! You can get the source code and try it yourself here – although, as before, you’ll need your own API token for Handwrytten’s API:


Give the Gift of Python

Share this post: