Day 20 of the Anvil Advent Calendar
Build a web app every day until Christmas, with nothing but Python!
Manage your party RSVPs
It’s the run-up to Christmas, and we know that means time is precious. Today’s app will buy you a little more of it for the all-important party prep by handling your party invites and RSVPs for you!
We built a web app to do just that, with nothing but Python. Here’s what it looks like:
Click here to clone the app, see the source code, and modify it however you like:
We’ll explain how we built the app, or you can go ahead and use it to send out your invites!
https://christmas-rsvp.anvil.app
Create the UI
We’re going to have a few different screens depending on whether a party is being added, or someone is responding to an RSVP. So, let’s have a blank Homepage and manage navigation using separate Forms. Our Homepage is just a nice background, and not much else:
We’ll create a new Form for creating a new party and sending out invites:
We’re going to make this a multi-user app using Anvil’s Users Service, so go ahead and add the Users Service to your App.
We’re also using Anvil’s Data Tables to store our parties and rsvps, and our tables look like this:
Send your invites
Next, we’ll write a server function to send out our invites. We’ll also add the party to our Data Tables as part of this function:
@anvil.server.callable
def send_invites(from_name,party_date,emails):
party = app_tables.parties.add_row(user=anvil.users.get_user(), date=party_date)
date_text = party_date.strftime('%d %B %Y, at %H:%M')
for email in emails:
anvil.email.send(from_name=from_name,
to=email,
subject="It's party time!",
text=f"""
You're invited to {from_name}'s Christmas party!
Please RSVP:
Follow this link if you'll be attending: https://christmas-rsvp.anvil.app/#?id={party.get_id()}&u={email}&r=yes<br><br>
Follow this link if you can't make it: https://christmas-rsvp.anvil.app/#?id={party.get_id()}&u={email}&r=no<br><br>
""",
html=f"""
<h1 style="color: #D32F2F">You're invited to {from_name}'s Christmas party!</h1>
{from_name} would love you to come to a Christmas party on {date_text}!<br><br>
Please RSVP:<br>
<a href="https://christmas-rsvp.anvil.app/#?id={party.get_id()}&u={email}&r=yes">Click here</a> if you'll be attending :)<br>
<a href="https://christmas-rsvp.anvil.app/#?id={party.get_id()}&u={email}&r=no">Click here</a> if you can't make it :(<br><br>
""")
return party
Outgoing email is subject to a monthly quota, depending on your account plan.
Email sent through a custom SMTP server does not count towards your monthly quota.
We’re giving our invitees two links to click - one if they’ll be attending, and one if they can’t make it. We’re then using the url hash to store details of the party, the respondent and the response so we can store our RSVPs.
If a user loads our app with no url hash, we can assume they’re there to create a new party, so we’ll ask them to log in and show them the form that lets them do just that:
from .NewParty import NewParty
def __init__(self, **properties):
# Set Form properties and Data Bindings.
self.init_components(**properties)
# Any code you write here will run before the form opens.
# If they're not responding, let them create a new party
if get_url_hash() is '':
anvil.users.login_with_form()
self.content_panel.add_component(NewParty())
We’ve marked our send_invites
server function as @anvil.server.callable
so we can call it from our client-side code. From our NewParty Form, we call the send_invites
function and pass on our user’s inputs when the ‘Send Invites’ button is clicked:
def invite_button_click(self, **event_args):
party_date = self.date_box.date
from_name = self.host_box.text
emails = self.email_box.text.split()
# send out invites
party = anvil.server.call('send_invites', from_name, party_date, emails)
Notification("Your invites have been sent!").show()
# go back to the Homepage
open_form('Homepage')
That’s the invites done!
Record RSVPs
Next, we’ll record our RSVPs as they come in. We have stored the id of the party, the respondent’s email address and the reply in the url hash for the RSVP links, so we can use this information to store the rsvp and let the host know.
Let’s write our server function first. This stores the rsvp, and emails the host letting them know the respondent’s reply.
@anvil.server.callable
def rsvp(party, respondent, rsvp):
reply = True if rsvp == 'yes' else False
app_tables.rsvp.add_row(party=party, email=respondent, rsvp=reply)
user_email = party['user']['email']
if reply:
response = "will"
else:
response = "won't"
anvil.email.send(from_name='Anvil party coordinators',
to=user_email,
subject="Party RSVP",
text=f"""
{respondent} has RSVP'd, and {response} be attending your party on {party['date'].strftime('%d %B %Y, at %H:%M')}
""",
html=f"""
<h1 style="color: #D32F2F">RSVP from {respondent}</h1>
{respondent} has RSVP'd, and {response} be attending your party on {party['date'].strftime('%d %B %Y, at %H:%M')}<br><br>
""")
Now, all we need to do is create a simple UI for people who are RSVP-ing:
We’ll use the url hash to decide whether to show this page or the NewParty form, by adjusting the code in the __init__
method of our Homepage:
from .NewParty import NewParty
from .RSVP import RSVP
class Homepage(HomepageTemplate):
def __init__(self, **properties):
# Set Form properties and Data Bindings.
self.init_components(**properties)
# Any code you write here will run before the form opens.
if get_url_hash() is '':
anvil.users.login_with_form()
self.content_panel.add_component(NewParty())
else:
self.content_panel.add_component(RSVP())
Finally, we’ll call our rsvp()
server function from our RSVP Form:
# Any code you write here will run before the form opens.
party_id = get_url_hash()['id']
party = app_tables.parties.get_by_id(party_id)
respondent = get_url_hash()['u']
rsvp = get_url_hash()['r']
anvil.server.call('rsvp', party, respondent, rsvp)
Now, your host will get an email each time they receive an RSVP!
Invites sent, RSVPs recorded. It’s time to party!
View the source code:
Give the Gift of Python
Share this post: