person:
first_namelast_nameemail (many emails for one person)email:
typeaddressDatabase programming in Python is based on the DB-API. Some supported databases:
Example:
import MySQLdb
conn = MySQLdb.connect(
db='test', username='ianb')
cur = conn.cursor()
cur.execute(
"SELECT id, first_name, last_name FROM person")
result = cur.fetchall()
for id, first_name, last_name in result:
print "%2i %s, %s" % (id, last_name, first_name)
MySQLdb,
psycopg, sqlite, etc) module.connect(...) to create a
connection. connection.cursor() to get a cursor. Cursors do
all the work. cursor.execute(sql_query) to run
something. cursor.fetchall() to get results.
The table:
| person | ||
|---|---|---|
| id | first_name | last_name |
| 1 | John | Doe |
| 2 | Tom | Jones |
| ... | ||
The class:
|
class Person(SQLObject):
# id is implicit
first_name = StringCol()
last_name = StringCol()
| |||||||||||||||
An instance:
|
>>> john = Person.get(1) >>> john.first_name 'John' | |||||||||||||||
__connection__ = 'postgres://pgsql@localhost/test'
class Person(SQLObject):
first_name = StringCol()
last_name = StringCol()
emails = MultipleJoin('Email')
class Email(SQLObject):
person = ForeignKey('Person')
type = EnumCol(['home', 'work'])
address = StringCol()
def createTables():
for table in (Person, Email):
table.createTable(ifNotExists=True)
>>> john = Person(first_name='John', last_name='Doe') >>> email = Email(person=john, type='home', ... address='john@work.com') >>> john.emails []
>>> tom = Person(first_name='Tom', last_name='Jones') >>> tom is Person.get(tom.id) True >>> list(Person.selectBy(first_name='John')) []
You can add extra methods:
class Person(SQLObject):
...
def _get_name(self):
return self.first_name + ' ' + self.last_name
>>> tom.name 'Tom Jones'
_get_attr() methods are called whenever the
obj.attr attribute is called _set_attr() methods are called whenever the
obj.attr = value statement is run _set_attr() is optional You can override columns:
class Person(SQLObject):
...
last_name_searchable = StringCol()
def _set_last_name(self, value):
self._SO_set_last_name(self, value)
self.last_name_lower = re.sub(r'[^a-zA-Z]', '', value).lower()
You can fiddle with the naming:
class Person(SQLObject):
_table = "people"
first_name = StringCol(dbName="fname")
...
Foreign Keys:
class Email(SQLObject):
person = ForeignKey('Person')
...
Note we use a string for 'Person'.
The other side of one-to-many:
class Person(SQLObject):
...
emails = MultipleJoin('Email')
Many to many relationships imply a "hidden" table:
class Address(SQLObject):
people = RelatedJoin('Person')
...
class Person(SQLObject):
addresses = RelatedJoin('Address')
The intermediate table created:
CREATE TABLE address_person ( address_id INT NOT NULL, person_id INT NOT NULL );
SQLObject can use reflection to figure out what columns your table has:
class Person(SQLObject):
_fromDatabase = True
You can start with _fromDatabase = True and add
in explicit columns, overriding defaults.
Person.get(id) to retrieve a rowPerson(first_name=...) to insert a row (the
new object is returned)aPerson.destroySelf() to delete a rowaPerson.first_name = "new_name"UPDATE is executed immediately aPerson.set(first_name="new_fname", last_name="new_lname") You can use Python expressions (kind of):
query = Person.q.first_name == "Joe"
Person.select(query)
Class.q.column_name creates a magical
object that creates queries.sqlrepr() turns these query objects into SQL (mostly
hidden)sqlrepr(Person.q.first_name == "Joe", 'mysql')
creates the SQL person.first_name =
'Joe'Complicated joins are possible:
Person.select((Person.q.id == Email.q.personID)
& (Email.q.address.startswith('joe')))
Becomes:
SELECT person.id, person.first_name, person.last_name
FROM person, email
WHERE person.id = email.person_id
AND email.address LIKE 'joe%'
LIMIT and OFFSET statements are added to your queryselect_result.count() to run
aggregate functions list(select_result)ORMs live in the world between Object Oriented programmers (and programs) and Relational programmers (and programs). Neither will be happy.
for loop is natural)
See the Python Wiki at: python.org/moin
The page is HigherLevelDatabaseProgramming.