ZODB for Python Programmers
- A Simple Example
- Detecting Changes
- A Complete Example
- Conclusion
- ZODB Resources
Zope Object Database (ZODB) is a powerful object database for Python objects that comes with Zope (http://www.zope.org). If you've ever worked with a relational database, such as PostgreSQL, MySQL, or Oracle, then you should be familiar with the role of a database. If not, just start by thinking of it as short or long-term storage for your application data.
For many tasks, relational databases are clearly a good solution, but sometimes relational databases don't fit well with your object model. If you have lots of different kinds of interconnected objects with complex relationships and changing schemas then ZODB might be worth giving a try.
A major feature of ZODB is transparency. You do not need to write any code to explicitly read or write your objects to or from a database. Just put your persistent objects into a container that works just like a Python dictionary. Everything inside this dictionary is saved in the database. This dictionary is said to be the root of the database. It's like a magic bag; any Python object that you put inside it becomes persistent.
Actually, there are a few restrictions on what you can store in the ZODB. You can store any objects that can be pickled into a standard, cross-platform serial format. Objects such as lists, dictionaries, and numbers can be pickled. Objects such as files, sockets, and Python code objects, cannot be stored in the database because they cannot be pickled. For more information on pickling, see the Python pickle module documentation (http://www.python.org/doc/current/lib/module-pickle.html).
A Simple Example
The first thing you need to do to start working with ZODB is to create a root object. This process involves first opening a connection to a storage, which is the actual back-end that stores your data.
ZODB supports many pluggable storage back-ends, but for the purposes of this article I'm going to show you how to use the FileStorage back-end storage, which stores your object data in a file. Other storages include storing objects in relational databases, Berkeley databases, and a client-to-server storage, which stores objects on a remote storage server.
To set up a ZODB, you must first install it. ZODB comes with Zope, so the easiest way to install ZODB is to install Zope and use the ZODB that comes with your Zope installation. For those of you who don't want all of Zope, but want ZODB, see the instructions for downloading StandaloneZODB from the ZODB (http://www.zope.org/Wikis/ZODB/FrontPage) web page.
StandaloneZODB can be installed into your system's Python libraries using the standard distutils Python module.
After installing ZODB, you can start to experiment with it right from the Python command-line interpreter. For example, try the following Python code in your interpreter:
>>> from ZODB import FileStorage, DB >>> storage = FileStorage.FileStorage('mydatabase.fs') >>> db = DB(storage) >>> connection = db.open() >>> root = connection.root()
Here, you create storage and use the mydatabse.fs file to store the object information. Then, you create a database that uses that storage.
Next, the database needs to be opened by calling the open() method. This returns a connection object to the database. The connection object then gives you access to the root of the database with the root() method.
The root object is the dictionary that holds all of your persistent objects. For example, you can store a simple list of strings in the root object:
>>> root['employees'] = ['Mary', 'Jo', 'Bob']
Now, you have changed the persistent database by adding a new object, but this change so far is only temporary. To make the change permanent you must commit the current transaction:
>>> get_transaction().commit()
Transactions group lots of changes into one atomic operation. In a later article, I'll show you how this is a very powerful feature. For now, you can think of committing transactions as checkpoints where you save the changes you've made to your objects so far. Later on, I'll show you how to abort those changes, and how to undo them after they are committed.
Now let's find out if our data was actually saved. First close the database connection:
>>> connection.close()
Then quit Python. Now start the Python interpreter up again, and connect to the database you just created:
>>> from ZODB import FileStorage, DB >>> storage = FileStorage.FileStorage('mydatabase.fs') >>> db = DB(storage) >>> connection = db.open() >>> root = connection.root()Now, let's see what's in the root:
>>> root.items() [('employees', ['Mary', 'Jo', 'Bob'])]
There's your list. If you had used a relational database, you would have had to issue a SQL query to save even a simple Python list, such as the preceding example. You would have also needed some code to convert a SQL query back into the list when you wanted to use it again. You don't have to do any of this work when using ZODB. Using ZODB is almost completely transparent; in fact, ZODB-based programs often look suspiciously simple!
Keep in mind that ZODB's persistent dictionary is just the tip of the persistence iceberg. Persistent objects can have attributes that are themselves persistent. In other words, even though you might have only one or two top-level persistent objects as values in the persistent dictionary, you can still have thousands of subobjects lower than them. This is, in fact, how Zope does it. In Zope, only one top-level object exists, which is the root application object for all other objects in Zope.