Model-View-Controller

The Model-View-Controller application design pattern is widely used by web frameworks, including Ruby on Rails.

Although there is some argument about the exact meaning of MVC and which application frameworks actually follow it, in its simplest sense it amounts to, the separation of the code that stores and retrieves data from the database, the code that displays the data, and the code that handles requests for data to be updated or displayed.

In the context of webapp2, it may be helpful to think of this pattern as Model-Template-Handler, because models, templates and handlers are what we are familiar with.

It is the models, templates and handlers that we need to separate out from our main application file.

####Deciding on an overall design

In a webapp2 application, this is what we start with:

app.py
app.yaml

We might then add a template directory:

app.py
app.yaml
templates/

We might then want to add handler and model directories:

app.py
app.yaml
handlers/
models/
templates/

We then might want to create files for all the handlers and models:

app.py
app.yaml
handlers/
  user_handler.py
  blog_handler.py
models/
  user.py
  blog.py
templates/

And for the templates:

app.py
app.yaml
handlers/
  blog_handler.py
  user_handler.py
models/
  blog.py
  user.py
templates/
  blog/
    index.html
    show.html
    edit.html
  user/
    index.html
    show.html
    edit.html

This layout is one option. It is not the only one.

####Adding __init__.py files

Having decided on a design, there is one more thing we need to do before we can start refactoring app.py: add empty __init__.py files:

__init__.py
app.py
app.yaml
handlers/
  __init__.py
  blog_handler.py
  user_handler.py
models/
  __init__.py
  blog.py
  user.py
templates/

These __init__.py files tell your application to treat the your directories as containing packages that can now be referenced in your code like this:

 import handlers.blog_handler

They need to be added to every directory inside your main directory that contains code that you might want to import.

####Refactoring your code

The task now is to take our existing code and and refactor it to reflect this new structure.

Probably the easiest way to start is to:

  1. Create empty versions of all the new files;
  2. Rename your existing app.py file to somethinlg like app_old.py;
  3. Create a new empty app.py application file.

Then start adding code to the new file:

  1. Start by moving the code for creating your app object out of the old app file and into the new one;
  2. Import the old file into the new one;
  3. Get your application running.

Your new app.py file might look something like this:

from webapp2 import WSGIApplication 
from app_old import * 

app = WSGIApplication(['/', MainHandler])

We have imported just the WSGIApplication class from webapp2 and we have imported everything (*) from app_old, so that we can access the handlers, like MainHandler, without having to explicitly reference the imported file, like app_old.MainHandler.

This is just the start. We now need to start separating out the code in app_old.py. Gradually start moving code, class-by-class and function-by-function, out of the old file.

As you separate the models from the handlers, you will need to add extra methods to your model classes. You will need a constructor (__init__) method for each model, which might look something like this:

class Post(db.Model):

  def __init__(self, id):
    key = db.Key.from_path('Post', int(post_id), parent=blog_key())
    self.data = db.get(key)

You will then be able to access the data by creating model objects in your handlers. Something like this:

class PostPage(BlogHandler):

  def get(self, post_id):
    p = Post(id)
    self.render("posts/show.html", post = p.data)

At the end of the process there should be no database code in the handlers and there should be no references to templates or rendering in the models.

Well done. You now have a nicely refactored application.