Forgetting On Purpose

For most applications, we never want to lose data, and we go to great lengths to make that happen. But what if we really only want data to be temporary? How does someone like Snapchat “forget” photos after five seconds? In this post, we’ll think about a hypothetical a messaging app where we want messages to expire after 30 minutes, no longer to be seen again. We’ll explore one way to tackle the problem in Django, although it certainly isn’t the only way.

Setting Up Our Model

Consider a pretty generic Message model object.

With this model, we don’t have to worry about manually setting the expiration date; it is set by default.

Getting Messages

Ok, so we can create messages, but that’s pretty basic. How do we retrieve messages? Say I’m logged in, and I want all my active (i.e. not expired) messages. One straightforward way to do this would be to query for all the messages that expire in the future:

But that’s a little bit clunky, and relies on us remembering to do that each time we want to get the data.

To help us out, we can use a custom manager so that we don’t have to do this each time. We add the following code to our model:

With this changed, we’ve modified the default manager for the Message class. We no longer have a message.objects property, but instead have a property that can only return a message if it’s active. As implemented, there’s no easy way to retrieve a message that has expired. We would need to add another manager to our Message class if we wanted the ability to see expired messages via model objects.

Furthermore, since we’ve specified that we use the ActiveMessagesManager for related fields, it will be used for our messages_sent and messages_received fields on User objects. This works nicely for our use case of getting the current user’s active messages.

So, now we don’t have to worry about making sure our queries filter out expired messages. Our custom manager takes care of this for us, and we can’t accidentally get an expired message by forgetting to query and filter properly.

The example model above is available as a Gist.

Other Considerations

Besides the pure model considerations, there are other things we need to think about to make temporary data. We acknowledge up front that it is not really possible to guarantee that the message is temporary (a user could simply copy and paste the data, or take a screenshot). But, we can take care of the obvious holes to ensure no that there isn’t accidental leakage of the data. Below are some things to think about.

  • Browser Caching Will the browser cache our message? Do we need to set response headers so that the browser won’t cache the data?
  • Web Crawlers Can we make web crawlers ignore pages with messages on them? Is robots.txt set to ignore pages with messages?
  • Use SSL We should probably encrypt the messages with SSL to help some with caching and privacy of messages.
  • Purge the Database We shouldn’t rely on just the model and queries to hide messages. We should probably have a periodic job that will actually delete expired messages from the database.
  • Backups Are our data backups capturing the temporary data? If so, is that something that we really want to do?

Thoughts or anything I’ve missed? Please leave a comment.

Image courtesy Andrew Butko, (CC BY-SA 3.0)

Leave a Reply

Your email address will not be published. Required fields are marked *