Creating a web app using Python in 15 minutes (installation included)

(and with Zope2 by the way).

  • You don't need to be superuser
  • You don't need to know Zope yet (we take care of that)
  • You don't need to know sql or any other database
  • You dont't need to be able to install Apache, IIS or any other web server.

Zope2 is a great framework that I've been using for more than 10 years to write somewhat complex (> 100 Ksloc), enterprise-grade, mission-critical web applications.

Zope2 has "ZMI", "Interfaces", "DTML" and much more, which can take some time to master, but the point is you don't need any of these to write simple web applications (and in fact, I practically don't use them). You can start by writing a simple web application, and then learn gradually more concepts as you need them. The purpose of this post is to help in this process.

Zope2 comes with its own integrated web server and persistence layer, meaning you don't need anything else to come with a production-grade service. No need for an additionnal web server, or a database, nothing.

The natural persistence layer in Zope2 is ZODB, an object-oriented database, meaning you can have a database (persistence) in your application, without knowing anything about databases, in particular you don't need SQL at all. All you need are your objects. And you don't even need to know ZODB at first ! It's transparent (quite).

The only thing you need to know (a bit) is Python.

There are a few things that Zope2 doesn't do very well, in particular HTTPS. For that, you might need another web server such as Apache or lighthttpd, but only as an HTTPS proxy, everything else is handled by Zope.

So let's go, we've already spent 2 in our 15 minutes reading this introduction.

First example: Hello world


 class HelloApp:
 
    def index_html(self):
        "My doc"
        return '<html><body><form action="hello">What is your name: <input name="yourName"></form></html>'
 
    def hello(self, yourName):
        "My doc"
        return "Hello " + yourName


How simpler could it be ? Actually, there are in Zope2 better ways to display a page than returning a string, but we'll stick to it for now.

We save this in a file HelloWorld.py.

The doc strings ("My doc") aren't very informative, but they serve an important purpose, since they tell zope that the method is published (can be called from the web). This is both good and bad. The good part is that, if a method doesn't have a docstring it can't be called from the web, so this mitigates the risk of having someone calling part of your program from the web, bypassing some security mechanisms, while it wasn't your purpose.

The bad thing is that, if a method does have a docstring, it may be called from the web, while your purpose in putting a docstring in the first place was to document your method, thus creating a potential security breach. So I advise putting docstring only for method being called from the web, and using another mechanism to document your code.

Installing the stuff (the gory details)

This is were it gets ritualistic (you don't understand why you do it, but you've to do it anyway). Fortunately, it happens only one and isn't that hard.

It comes in two parts: installing the Zope framework, and putting your code into the server (this is called "making your code a product").

Installing the Zope framework

A little help from your root friend:

# aptitude install python-dev python-setuptools
# easy_install virtualenv

Now, as yourself, we put all the environment in ~/z

mkdir ~/z
virtualenv ~/z # This create all you need in ~/z
cd ~/z
./bin/easy_install Zope2

You may have some errors about an invalid syntax with metaclass=metaclass, don't worry about them.

Zope2 is installed, now you create an instance for your app, let's put it in ~/z/var/myapp

mkdir var/myapp
./bin/mkzopeinstance ~/z/var/myapp

Now, if you perform a

ls var/myapp

You'll see many important directories: in bin are some tools, var will host your database, log as the name implies and Products is where your code will go.

Turning your code into a Zope "product"

Introducing persistence: a more complex application

You're writing an application to keep track of the score of the students in our class. So we have a Course class to describe each course, and a class Student to keep track of the name and score of each student.

 class Course(Persistent):

    def __init__(self):
        self.students = { }
 
    def addStudent(self, name):
        if self.students.has_key(name):
            raise Exception('student %s already added' % name)
        self.students[name] = Student(name)
 
    def index_html(self):
       
        

Installing zope2 (under Unix / Linux)

You don't need to be superuser (except to run Zope on a privileged port).

We'll install it in a python virtual environment, this has many advantages, even in production environment, that all boil down to the ability to have several separate complete instances on your machine:

  • when upgrading, you can then have the old and new instances on your machine at the same time, making a rollback particularly easy
  • If several developers share the same server, each of them can have its own instance
  • etc...

It's very easy to have one separate database for each instance in Zope when using ZODB (the natural database for Zope), since there is no need to have a separate database server.

Let's go

Advantages of Zope vs other frameworks

You can always write some decent stuff with, say, apache .cgi stuff and the python cgi library. However, if your project gets more complex, there some issues where you'll need a real framework, in particular security, persistence and to a lesser extent templates. Zope solves them all in an elegant and efficient way.

Security

Persistence

Zope comes with its own persistence layer (ZODB), which is efficient in every respect

  • Simpler administration, since you don't need to setup a mysql, mariadb or other database server
  • much more CPU efficient, since the persistence layer runs inside the application server process
    • no need to make a context switch between the application server and the database
    • no network or interprocess communication involved, the database and application server share the same memory space
  • Space efficient (to some extent): the data only occupies the needed space on the disk. Only the used fields are stored in the database, no need to reserve space for unused fields.
  • Simpler to program: the data "is there", there's no need to fetch data at the beginning of a method and to send it back to the database: access a dictionary or an object field, and the data is fetched, modify it, and the data will be sent back to the database at the end of the transaction. The commit / rollback is automatic by default.
  • Nothing special to do when you extend your data model, no "add column", nothing. Just add the data inside your application, and it'll go into the database.

There is another flip to the coin however:

  • Since there is no database server, other processes or functional modules can't access data through the database, they can only do it through the application server.
  • Since you don't describe your data structure, there is no control by the database, they must be all inside your application, or you must write "auditing" code to be run on a regular basis to ensure the data in the database stay consistent.

Templates

More to come

Permissions

ACID properties