Personal tools
You are here: Home Documentation Tutorials Adder: an adding machine sample application A Grok Application and a Grok Model

A Grok Application and a Grok Model

A Grok Application is something that can be installed. A Grok Model is an object that is saved in the Zope Object Database.
The most basic Grok app that is still of some use: an adding machine with tape.
Page 2 of 4.

If you aren't following along with your own copy of the Adder application, you may find it helpful to refer to the main app.py file for the Adder application.

The convention in Grok is to put the code that you are developing for your application in a directory called src. If you look inside that directory you will see a package named adder. Inside that package you will see a file named app.py that contains the entire Adder application. Let's look at this file an see what it's doing.

import grok
from persistent.list import PersistentList

The grok package provides all of the core imports for creating a Grok application. The PersistentList class acts as an ordinary Python list that knows when it's been modified so that it can be transparently saved to the ZODB.

class Adder(grok.Application, grok.Model):
    """An adding machine with tape

    >>> adder = Adder()
    >>> adder.total
    0.0
    >>> adder.addTerm(0)
    0.0
    >>> '%.2f' % adder.addTerm(1.2)
    '1.20'
    >>> '%.2f' % adder.addTerm(-1)
    '0.20'

    Besides adding, Adder also contains a history of the added terms

    >>> ['%.2f' % term for term in adder.terms]
    ['0.00', '1.20', '-1.00']

    """

Every Grok application must have a single class that inherits from grok.Application. This will act as the root object for your application, depending on the size and scope of the application you are building you may use instances of this class to store things such as application specific settings and configuration. The Adder application also inherits from grok.Model, normally you will put your Models in seperate classes but since the Adder application is so simple, we can have a single class do double-duty as both an Application and a Model.

The docstring for the Adder class contains an example use of the class. You can try this code out for yourself on the Python interpreter. You will need to use a special version of the interpreter that has loaded Grok and Zope with your projects configuration, you can launch this with the zopectl command:

$ ./bin/zopectl debug
Welcome to the Zope 3 "debugger".
The application root object is available as the root variable.
A Zope debugger instance is available as the debugger (aka app) variable.

>>> from adder.app import Adder
>>> adder = Adder()

This example use code can also be programmatically fed into a Python interpreter and the expected output compared to the actual output. This form of automatically testing your application is called doctesting and is a very simple, easy concise way of adding tests to your application.

Remember when you created a new instance of the Adder application using the Grok Administration interface? This action called the constructor method of this Adder class.

def __init__(self):
    super(Adder, self).__init__()
    self.message = None
    self.clear()

Because we are defining our own __init__ method that overrides the default one supplied by the grok.Application base class, we must call super() to perform the necessary actions in that class. We then store a message attribute on the instance of our Adder application, and call a clear() method to reset our adding machine to 0. We define the clear() method next.

def clear(self):
    self.terms = PersistentList()
    self.total = 0.0

Here we assign an attribute called terms to an instance of the PersistentList class. We are tying our data model to the ZODB, an embedable Python object database by inheriting from a Persistent class in the persistent package. This uses the normal Python pickle module to store Python objects on disk in a transactionally safe manner. However, because Python Lists and Dictionaries are mutable objects, there is no way for instances of the Adder class to know when attributes that contain these data strucutres have been modified. The easiest solution to this problem is to use special PersistentList and PersistentDict objects from the persistent package.

Our adding machine needs to know how to update itself. We define this as part of our application model. When you are creating a web application it is important to seperate the application logic from the view logic that deals with rendering and responding to HTTP requests. Your application logic should never contain anything such as HTML output or parsing user input, but should only concern itself with expressing the intent of your application.

def addTerm(self, term):
    self.terms.append(term)
    self.total += term
    return self.total