Simple Examples

Documentation Index

  1. Initialization
  2. Database Creation
  3. Defining and Interacting With Objects
  4. Finding Objects
  5. Class Methods
  6. Validations
  7. DBAPI Column Objects

Since Twistar uses Twisted, most methods and function calls will return a twisted.internet.defer.Deferred object. You must understand the proper use of these objects before most of this documentation will make sense.

Initialization

Before using Twistar a connection to the DB must be made. To connect to the database use Twisted's twisted.enterprise.adapi module and the ConnectionPool object. The Registry class is used to keep track of that pool. For instance, this is the method to specify a connection to a MySQL database:

1 2 3 4

from twisted.enterprise import adbapi from twistar.registry import Registry Registry.DBPOOL = adbapi.ConnectionPool('MySQLdb', user="twistar", passwd="apass", db="twistar")

The modules implementing DBAPI that are supported by Twistar are:

Database Creation

Twistar does not provide DB creation / migration functionality beyond asynchronously making SQL queries. There are plenty of utilities in existance to provide these capabilities. If you need to create tables in an asynchronous manner, you can always execute the creation SQL directly.

Objects will assume that the plural version of the object's class name will be the table name. For instance, if the class name is Person, then the tablename should be People. If it is Chicken, the tablename should be Chickens. If you want to manually specify a tablename, you can do that with the TABLENAME class variable (see the DBObject definition).

Column names should have no spaces (with words separated by a _) and should generally be lower case. All object tables (that don't describe relationships) should have an auto-incrementing integer column named id.

Defining and Interacting With Objects

Objects representing rows in a database need only extend the DBObject class.

1 2 3 4

from twistar.dbobject import DBObject class User(DBObject): pass

Assuming that the users table has some VARCHAR fields like first_name and last_name and, say, and integer field named age (along with the required auto-incrementing integer column named id), then object properties can be assigned:

1 2 3 4 5 6 7 8 9 10 11 12

def done(user): print "A user has just been saved with id: %i" % user.id u = User() u.first_name = "John" u.last_name = "Smith" u.age = 25 u.save().addCallback(done) # The following is equivalent u = User(first_name="John", last_name="Smith", age=25) u.save().addCallback(done)

Any additional properties that are set that don't correspond to column names are ignored on the save. For instance, had a middle_name property been set for the user it would have simply been ignored when the object was saved.

Methods you would traditionally find in an active record style RDBMS are also available, for instance to test for existance and delete an object instance.

Finding Objects

To find an object, use the class's find method. It accepts a number of arguments to group, sort, and limit results. The simplest way to use the method is to get an object instance by id. For instance, if we wanted to find the user with an id of 1:

1

User.find(1).addCallback(...)

Additional constriants can be specified using the where paramter and others:

1

User.find(where=['first_name = ? AND last_name = ?', "John", "Smith"], limit=1).addCallback(...)

There are many more options, all of which are described on the DBObject API reference page.

One thing to note: if either limit is set to 1 or the query is by id, then the resulting deferred will return either the found object or None if not found. Otherwise, an array is returned containing the found objects.

Class Methods

Additional class methods (other than find) includes ones for getting an array of all objects (using the all() method), deleting all instances (using the deleteAll() method), getting a count of all instances (using the count() method), and determining whether or not any particular objects exist (using the exists() method). For instance:

1 2 3 4 5 6 7 8 9 10 11 12 13 14

def printAll(users): for user in users: print "First: %s Last: %s" % (user.first_name, user.last_name) User.all().addCallback(printAll) def printExists(doesExist): if doesExist: print "User exists!" else: print "User does not exist." User.exists(['first_name = ?', "John"]).addCallback(printExists)

Validations

Twistar also supports validations. Validations describe constraints on an object's parameters. If those constraints are violated, then an object will not be saved (this includes both creating and updating). In such a case a special parameter in the object keeps track of the errors and the messages.

As an example, let's say that we want all users to have a first name set and a last name that has a length between 1 and 256 characters. First, we describe the class User as above and then add restrictions on it.

1 2 3 4

class User(DBObject): pass User.validatesPresenceOf('first_name') User.validatesLengthOf('last_name', range=xrange(1,257))

If we look at an object without those parameters, it will be invalid:

1 2 3 4 5

def vcheck(isValid, object): if not isValid: print "Object not valid: %s" % str(u.errors) u = User() u.isValid().addCallback(vcheck, u)

If we try to save an invalid object, nothing happens:

1 2 3 4 5 6

def checkUser(user): print user.id # this will be None print user.errors.errorsFor('first_name') print user.errors.errorsFor('last_name') print "There were %d errors" % len(user.errors) User().save().addCallback(checkUser)

You can also create your own validity function. It should accept an object as a parameter and then add errors as necessary. It can return a Deferred if necessary; the return value from the function will be ignored.

1 2 3 4 5 6 7 8 9 10

def myValidator(user): if user.first_name != "fred": user.errors.add('first_name', "must be Fred!") User.addValidator(myValidator) def test(user): # This will print "First Name must be Fred!" print user.errors print user.id # None User(first_name='not fred').save().addCallback(test)

For more information see the Validator and Errors classes.

DBAPI Column Objects

The DBAPI specification requires that implementing modules define classes corresponding to certain column types (like the class Date). Twistar provides a driver agnostic method for using those classes using the Registry class:

1 2

Date = Registry.getDBAPIClass("Date") bob = User(first_name="Bob", dob=Date(1970, 1, 1))

Then, regardless of which DBAPI module you are using, your code will always be using the correct Date class.

Documentation Index