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:



Loading video...

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: