Tutorial

In this tutorial, we will create a simple blog application. You can learn to cache with rc and Python here. In our blog application, anyone can add or update a post, view all posts.

Create Skeleton

For this simple web application, we choose to use Flask. Here is the basic skeleton:

# -*- coding: utf-8 -*-
import time

from flask import Flask
from flask import request, url_for, redirect, abort, render_template_string
from flask_sqlalchemy import SQLAlchemy
from rc import Cache


app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
db = SQLAlchemy(app)
cache = Cache()


def init_db():
    db.create_all()


if __name__ == '__main__':
    init_db()
    app.run()

Create Models

Let’s declare the models and create the database schema here:

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False)
    content = db.Column(db.Text, nullable=False)
    created_ts = db.Column(db.Integer, nullable=False)
    updated_ts = db.Column(db.Integer, nullable=False)

    def __init__(self, title, content, created_ts, updated_ts):
        self.title = title
        self.content = content
        self.created_ts = created_ts
        self.updated_ts = updated_ts

    def __repr__(self):
        return '<Post %s>' % self.id

    @staticmethod
    def add(title, content):
        current_ts = int(time.time())
        post = Post(title, content, current_ts, current_ts)
        db.session.add(post)
        db.session.commit()
        cache.invalidate(Post.get_by_id, post.id)
        cache.invalidate(Post.get_all_ids)

    @staticmethod
    def update(post_id, title, content):
        post = Post.query.get(post_id)
        post.title = title
        post.content = content
        post.updated_ts = int(time.time())
        db.session.commit()
        cache.invalidate(Post.get_by_id, post.id)

    @staticmethod
    @cache.cache()
    def get_all_ids():
        posts = Post.query.all()
        return [post.id for post in posts]

    @staticmethod
    @cache.cache()
    def get_by_id(post_id):
        post = Post.query.get(post_id)
        return dict(id=post.id, title=post.title, content=post.content,
                    created_ts=post.created_ts, updated_ts=post.updated_ts)

View Functions

We will have four view functions here, they are used to add or update or view a single post, view all posts. The code explains itself:

@app.route('/add', methods=['POST'])
def add_post():
    title = request.form['title']
    content = request.form['content']
    Post.add(title, content)
    return redirect(url_for('show_all_posts'))


@app.route('/post/<int:post_id>')
def show_post(post_id):
    post = Post.get_by_id(post_id)
    if post is None:
        abort(404)
    return render_template_string(SHOW_POST_TEMPLATE, post=post)


@app.route('/post/<int:post_id>', methods=['POST'])
def edit_post(post_id):
    post = Post.get_by_id(post_id)
    if post is None:
        abort(404)
    title = request.form['title']
    content = request.form['content']
    Post.update(post_id, title, content)
    return redirect(url_for('show_all_posts'))


@app.route('/')
def show_all_posts():
    all_post_ids = Post.get_all_ids()
    all_posts = []
    with cache.batch_mode():
        for post_id in all_post_ids:
            all_posts.append(Post.get_by_id(post_id))
    all_posts = [p.value for p in all_posts]
    return render_template_string(ALL_POSTS_TEMPLATE, all_posts=all_posts)

Add The Templates

The template for showing all posts is here.

<!DOCTYPE html>
<html>
  <head>
    <title>Blog</title>
  </head>
  <body>
    <h1>Blog</h1>
    <form action="{{ url_for('add_post') }}" method=post>
      <dl>
        <dt>Title:
        <dd><input type=text size=50 name=title>
        <dt>Content:
        <dd><textarea name=content rows=5 cols=40></textarea>
        <dd><input type=submit value=Post>
      </dl>
    </form>
    <ul>
    {% for post in all_posts %}
      <li>
        <a href="{{ url_for('show_post', post_id=post.id) }}">
          {{ post.title }}
        </a>
      </li>
    {% endfor %}
    </ul>
  </body>
</html>

The template for showing one post is here.

<!DOCTYPE html>
<html>
  <head>
    <title>{{ post.title }}</title>
  </head>
  <body>
    <h1>{{ post.title }}</h1>
    <p>{{ post.content }}</p>
    <form action="{{ url_for('edit_post', post_id=post.id) }}" method=post>
      <dl>
        <dt>Title:
        <dd><input type=text size=50 name=title>
        <dt>Content:
        <dd><textarea name=content rows=5 cols=40></textarea>
        <dd><input type=submit value=Update>
      </dl>
    </form>
  </body>
</html>

If you want the full source code check out the tutorial source.