How To Love ZODB and Forget RDBMS - Part III |
Created by adytumsolutions . Last modified 2004-03-17 04:19:19. |
Where Do I Put My Stuff? |
RDBMS If you have a background in Relational Database Management Systems, then you are familiar with databases, tables, schemas, etc. Let's summarize the things we need for an RDBMS:
ZODB So what do you do in ZODB's object oriented framework? Well, conceptually, it's pretty much the same thing; you just go about it differently. Let's talk about the things we have already done so far. We have:
These two were done in the previous section with the following code in interactive python: >>> import ZODB.config >>> db = ZODB.config.databaseFromURL('pymonitor.conf') >>> conn = db.open() >>> dbroot = conn.root() We still need the following:
But right now, let's take care of the database. We have the database software installed and ready to go and we have a connection to it already. We promised to explain the reason for using the name In SQL, we would create our database like this: CREATE DATABASE monitoring_db; Just in like in the SQL example, for ZODB we'll need to give our database a name but we'll also have to decide what type of database it will be. Remember: object oriented databases are hierarchies, and there are many different ways to create hierarchies in Python. One type that scales particularly well is BTree (see the " Persistent-Aware Types" section in Advanced ZODB for Python Programmers for more details). Being the optimists we are, we think we might have millions of records (for our million servers and services we want to monitor!), so we decide to use BTree (in particular, we choose the OOBTree). Still using interactive python, we do the following: >>> from BTrees.OOBTree import OOBTree >>> dbname = 'monitoring_db' >>> dbroot[dbname] = OOBTree() >>> mondb = dbroot[dbname] Code Breakdown : The first line should look familiar now: we are importing the python modules necessary to create our BTree database. Line two is a simple assignment of the database name to a variable, and the database is actually created on the third line. We've got our database, but calling it by the name All we have left to do now is
Schemas In order to talk about table schemas, we should have a clear idea of what tables are and the components of a table:
This is very basic and not very technical, but you get the idea. Now, let's take a practical example. Let's say you want to have a table that keeps track of services you monitor on a server. Perhaps you want to monitor your Apache Web Server and your Zope Application Server. You want to know things about them like:
These are just some of the things we could know about each service. We might also find the following interesting as well:
SQL Schemas From all of these, we can build a table schema, and it might look something like this: +==================+ | service_table | +==================+ |id | |name | |description | |service | |hostname | |state_current | |state_last | |time_lastcheck | |time_lastok | |time_lastwarn | |time_lasterr | +==================+ Then, after connecting to the database, you might run something like this: CREATE TABLE service_table ( id VARCHAR(15) name VARCHAR(30) ... ); creating all your fields in the table. Python Schemas for ZODB We are using python to interact with the ZODB, so if the ZODB doesn't use tables like SQL, what does it use? We will also use a schema, but that schema is more than just a symbol or drawing: it's actually useful. Instead of tables, we have objects; instead of fields in a table, we have object attributes. Our schema (class) will actually be instantiated as an object. Once it's instantiated, we can store data in it. First, let's make our schema: >>> from Persistence import Persistent >>> class ServiceTable(Persistent): ... def __init__(self): ... self.id = '' ... self.name = '' ... self.description = '' ... self.service = '' ... self.hostname = '' ... self.state_current = '' ... self.state_last = '' ... self.time_lastcheck = '' ... self.time_lastok = '' ... self.time_lastwarn = '' ... self.time_lasterror = '' Now, this maintains our analogy with relational tables... however, let's give this some further thought (as Kapil Thangavelu gave me in an email!): if we imagine having just entered some data into this, what we will have is a record set, or a row of data. The table is a collection of rows, so it would be more conceptually accurate to call this class >>> from Persistence import Persistent >>> class ServiceRow(Persistent): ... def __init__(self): ... self.id = '' ... self.name = '' ... self.description = '' ... self.service = '' ... self.hostname = '' ... self.state_current = '' ... self.state_last = '' ... self.time_lastcheck = '' ... self.time_lastok = '' ... self.time_lastwarn = '' ... self.time_lasterror = '' Code Breakdown : We won't go over the details of python classes here, but suffice it to say that we just created a special class called With our schema setup, we can now instantiate it (like creating the SQL table, only we're doing it one row at a time): >>> newmon = ServiceRow() That's it! For each new row of data we want to add (service whose data we want to store), we will do the same thing: instantiate the ServiceRow schema. Once that's done, we can start adding/updating data. We'll give it a unique id and add some test data: >>> newmon.id = 'myserver.hostingcompany.com-httpd' >>> newmon.name = 'Apache Web Server' >>> newmon.description = 'This is the staging Web Server Service for 16 low-volume clients' >>> newmon.service = 'httpd' >>> newmon.hostname = 'myserver' >>> newmon.state_current = 'OK' >>> newmon.state_last = 'OK' >>> mondb[newmon.id] = newmon >>> get_transaction().commit() Code Breakdown : Most of this should be pretty evident: we are simply giving string values for various Though you can't prove it yet, you've successfully added data to a ZODB database! But how do we look at it? On to Part IV |
Comment
incorrect sample
Posted by: xavier_g at 2006-03-25from Persistence import Persistent
should be
from persistent import Persistent
at least in zodb 3.6
Comment
another bug
Posted by: xavier_g at 2006-03-25get_transaction seems to have been depricated since 3.4. Now you write:
import transaction transaction.get()