The following code models a simple system that tracks the transfer of
construction tools between jobs.  Equip (equipment) is transferred
between Jobs via Shipments.

Towards the end I attempt to map a class to a select statement in
order to make reporting simple.  Instead of dealing with sql to do the
reporting, I wanted to map an object to a summarizing sql statement,
and create a sort of object model that covers most of the summarizing
I will need to do.

I can't figure out how to map an object to a select statement and
include a relation in the object.  The code below should run in python
2.6:


from sqlalchemy import *
from sqlalchemy.orm import mapper, sessionmaker, relation
from sqlalchemy.sql import *
from datetime import date

# SA objects
db = create_engine('sqlite://', echo=True)
meta = MetaData()
session = sessionmaker(bind=db)()

# Table schema
job = Table('job', meta,
        Column('id', Integer, primary_key=True),
        Column('number', Integer))

equip = Table('equip', meta,
        Column('id', Integer, primary_key=True),
        Column('name', Unicode(255)))

equip_shipment = Table('equip_shipment', meta,
        Column('id', Integer, primary_key=True),
        Column('shipDate', Date),
        Column('fromJobId', Integer, ForeignKey('job.id')),
        Column('toJobId', Integer, ForeignKey('job.id')),
        Column('isBroken', Boolean))

equip_shipment_item = Table('equip_shipment_item', meta,
        Column('id', Integer, primary_key=True),
        Column('shipmentId', Integer, ForeignKey
('equip_shipment.id')),
        Column('equipId', Integer, ForeignKey('equip.id')),
        Column('qty', Integer))
meta.create_all(db)

# Objects
class KeywordInitMixin(object):
    '''Fills object's attributes with whatever keyword args were given
to init.

    As an example, allows me to simply inherit from this class like
this:

    class Test(KeywordInitMixin):
        pass

    ...And then create objects like this:

    t = Test(foo=1, bar='spam')
    assert t.foo == 1
    assert t.bar == 'spam'
    '''
    def __init__(self, **kwargs):
        for attr in self.ATTRS:
            if attr in kwargs:
                setattr(self, attr, kwargs[attr])
            else:
                setattr(self, attr, None)
        # Set any properties
        for attr, val in kwargs.items():
            # See if class has a property by this name
            if (hasattr(self.__class__, attr) and
            getattr(self.__class__, attr).__class__ is property):
                setattr(self, attr, val)
    def __repr__(self):
        args = ['%s=%s' % (arg, val) for arg, val in
self.__dict__.items() if
                arg in self.ATTRS and val]
        args = ', '.join(args)
        name = self.__class__.__name__
        result = '%s(%s)' % (name, args)
        return result

class Job(KeywordInitMixin):
    ATTRS = ['number']
class Equip(KeywordInitMixin):
    ATTRS = ['name']
class Shipment(KeywordInitMixin):
    ATTRS = ['shipDate', 'fromJob', 'toJob', 'isBroken']
class ShipmentItem(KeywordInitMixin):
    ATTRS = ['shipment', 'equip', 'qty']

# Map schema to objects
mapper(Job, job)
mapper(Equip, equip)
mapper(Shipment, equip_shipment,
        properties={
            'fromJob': relation(Job,
                primaryjoin=equip_shipment.c.fromJobId==job.c.id),
            'toJob': relation(Job,
                primaryjoin=equip_shipment.c.toJobId==job.c.id),
            }
        )
mapper(ShipmentItem, equip_shipment_item,
        properties={
            'shipment': relation(Shipment, backref='items'),
            'equip': relation(Equip)
            }
        )

# -------------------------------------
# Create some test data
# -------------------------------------
# Jobs
warehouse1 = Job(number=10001)
job1 = Job(number=11111)
job2 = Job(number=22222)
# Equipment
bClamps = Equip(name=u'Bridge Clamps')
cLocks = Equip(name=u'420 Channel Lock')
smallLock = Equip(name=u'Small 3210 Lock')
toolChest = Equip(name=u'Tool Chest')
# Add to orm
session.add_all([warehouse1, job1, job2, bClamps, cLocks])
# Ship tools to job 1
ship1 = Shipment(fromJob=warehouse1, toJob=job1, shipDate=date.today
())
ship1.items.append(ShipmentItem(qty=5, equip=bClamps))
# Transfer tools from job 1 to job 2
ship2 = Shipment(fromJob=job1, toJob=job2, shipDate=date.today())
ship2.items.append(ShipmentItem(qty=2, equip=bClamps))
# Job 1 returns some tools to the warehouse
ship3 = Shipment(fromJob=job1, toJob=warehouse1, shipDate=date.today
())
ship3.loadedBy = ship3.deliveredBy = 'jane doe'
ship3.items.append(ShipmentItem(qty=2, equip=smallLock))
# Add to orm
session.add_all([ship1, ship2, ship3])
# Job 1 breaks some tools
broken = Shipment(fromJob=job1, isBroken=True, shipDate=date.today())
broken.items.append(ShipmentItem(qty=1, equip=smallLock))
# Break more of same equip, but in different line item to test
aggregation
broken.items.append(ShipmentItem(qty=4, equip=smallLock))
# Job 2 breaks stuff too
broken2 = Shipment(fromJob=job2, isBroken=True, shipDate=date.today())
broken2.items.append(ShipmentItem(qty=1, equip=bClamps))
# Save
session.add_all([broken, broken2])
session.flush()
session.commit()

# -------------------------------------
# Create read-only reporting object that is based on a query that
# summarizes the equipment that has been broken by each job.
# -------------------------------------
class BrokenItem(object):
    '''One row for each piece of equipment that a job has broken, and
    the qty that has been broken.'''
    pass

SELECT = [
    equip_shipment.c.fromJobId,
    equip.c.name.label('equip'),
    func.sum(equip_shipment_item.c.qty).label('broken'),
    ]
FROM = [equip_shipment_item.join(equip_shipment).join(equip)]
sql = select(SELECT, from_obj=FROM)
sql = sql.where(equip_shipment.c.isBroken==True)
sql = sql.group_by(equip.c.name)
sql = sql.alias()

# Map to object
props = {
        'job': relation(Job)
        }
# I chose a primary key here because SA needs one
mapper(BrokenItem, sql, properties=props, primary_key=
[sql.c.fromJobId])

# ----------------------------------
# Test report object
# ----------------------------------
# Find what job 22222 has broke
# !! This causes an error because the table is joined in a way that
there
# is a row returned for each job !!
broke = session.query(BrokenItem).filter(Job.number==22222).one()

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to