db: change ForeignKey columns to use _id suffix; start using SQLAlchemy ORM for Order model
authorTero Marttila <terom@fixme.fi>
Fri, 31 Dec 2010 01:05:24 +0200
changeset 25 cfb55708ee03
parent 24 50a63155b244
child 26 04bf578d358a
db: change ForeignKey columns to use _id suffix; start using SQLAlchemy ORM for Order model
svv/application.py
svv/database.py
svv/orders.py
--- a/svv/application.py	Thu Dec 30 23:54:38 2010 +0200
+++ b/svv/application.py	Fri Dec 31 01:05:24 2010 +0200
@@ -83,3 +83,13 @@
 
         self.engine.execute(sql, **values)
 
+    # XXX: rename this to something else, conflicts, to some degree, with web session with cookies (although using
+    # SQL transctions at that level would be pretty cool..)
+    # orm orm_session objects dbsession dbmapping dbmaps 
+    def session (self) :
+        """
+            Return a new SQLAlchemy database session, for use with ORM mapped objects.
+        """
+
+        return db.session_factory(bind=self.engine)
+
--- a/svv/database.py	Thu Dec 30 23:54:38 2010 +0200
+++ b/svv/database.py	Fri Dec 31 01:05:24 2010 +0200
@@ -6,6 +6,12 @@
 
 from sqlalchemy import *
 
+# for ORM definitions; outside of this module
+from sqlalchemy.orm import mapper, sessionmaker
+
+# used by Application.session
+session_factory = sessionmaker()
+
 # our schema
 schema = MetaData()
 
@@ -33,7 +39,7 @@
         Column('id', Integer, primary_key=True),
 
         # reference to contact being primary for specified customer (organization or themselves)
-        Column('customer', None, ForeignKey('customers.id'), nullable=True),
+        Column('customer_id', None, ForeignKey('customers.id'), nullable=True),
 
         # person's natural name
         Column('name', Unicode, nullable=True),
@@ -55,10 +61,10 @@
         Column('id', Integer, primary_key=True),
 
         # ordering customer, if entered (i.e. who to bill)
-        Column('customer', None, ForeignKey('customers.id'), nullable=True),
+        Column('customer_id', None, ForeignKey('customers.id'), nullable=True),
 
         # active contact at customer side for order (i.e. who to call)
-        Column('contact', None, ForeignKey('contacts.id'), nullable=True),
+        Column('contact_id', None, ForeignKey('contacts.id'), nullable=True),
 
         # short description of customer event where these items are going
         Column('event_name', Unicode, nullable=True),
--- a/svv/orders.py	Thu Dec 30 23:54:38 2010 +0200
+++ b/svv/orders.py	Fri Dec 31 01:05:24 2010 +0200
@@ -22,6 +22,62 @@
 
 log = logging.getLogger('svv.orders')
 
+class Customer (object) :
+    """
+        Data-mapping for the customers table
+    """
+    
+    # customer name (organization or natural person)
+    name = None
+
+class Contact (object) :
+    """
+        Data-mapping for the contacts table
+    """
+
+    # human-readable details
+    name = None
+    phone = None
+    email = None
+
+    # relation to Customer
+    customer = None
+
+
+class Order (object) :
+    """
+        Data-mapping for orders table.
+    """
+
+    # relation to Customer
+    customer = None
+    
+    # relation to Contact
+    contact = None
+    
+    # event info
+    event_name = None
+    event_description = None
+    event_start = None
+    event_end = None
+
+    def __init__ (self) :
+        """
+            Construct an Order with default values
+        """
+        
+        ## Set default values
+        tomorrow = datetime.date.today() + datetime.timedelta(days=1)
+        
+        # default to tomorrow afternoon
+        self.event_start = datetime.datetime.combine(tomorrow, datetime.time(16, 00))
+        self.event_end = None   # determined by UI behaviour
+        
+# bind against database schema
+db.mapper(Customer, db.customers)
+db.mapper(Contact, db.contacts)
+db.mapper(Order, db.orders)
+
 class FormError (Exception) :
     """
         A user-level error in a form field
@@ -395,7 +451,7 @@
                     ('contact_name', db.contacts.c.name, contact_name),
                     ('contact_phone', db.contacts.c.phone, contact_phone),
                     ('contact_email', db.contacts.c.email, contact_email),
-                    ('contact_customer', db.contacts.c.customer, contact_customer),
+                    ('contact_customer', db.contacts.c.customer_id, contact_customer),
                 ),
             )
 
@@ -463,7 +519,7 @@
         """
         
         # query tables from db
-        sql_from = db.orders.join(db.customers).join(db.contacts, (db.orders.c.contact == db.contacts.c.id))
+        sql_from = db.orders.join(db.customers).join(db.contacts, (db.orders.c.contact_id == db.contacts.c.id))
         sql = db.select(
             [
                 db.orders,
@@ -513,7 +569,7 @@
         sql = db.select([db.contacts.c.id, db.contacts.c.name, db.contacts.c.phone, db.contacts.c.email])
 
         if customer_id :
-            sql = sql.where((db.contacts.c.customer == customer_id))
+            sql = sql.where((db.contacts.c.customer_id == customer_id))
 
         return self.app.query(sql)
 
@@ -812,14 +868,14 @@
             tuples, ordered by event_start, per default
         """
         
-        sql_from = db.orders.join(db.customers).join(db.contacts, (db.contacts.c.id == db.orders.c.contact))
+        sql_from = db.orders.join(db.customers).join(db.contacts, (db.contacts.c.id == db.orders.c.contact_id))
         sql = db.select(
             [
                 db.orders.c.id,
-                db.orders.c.customer,
+                db.orders.c.customer_id,
                 db.customers.c.name,
                 db.orders.c.event_name,
-                db.orders.c.contact,
+                db.orders.c.contact_id,
                 db.contacts.c.name,
                 db.orders.c.event_start,
                 db.orders.c.event_end,
@@ -934,9 +990,9 @@
 
                 # Tilaaja
                 tags.td(
-                    tags.a(href=self.url_for(urls.CustomerView, id=row[db.orders.c.customer]))(
+                    tags.a(href=self.url_for(urls.CustomerView, id=row[db.orders.c.customer_id]))(
                         row[db.customers.c.name]
-                    ) if row[db.orders.c.customer] else "-"
+                    ) if row[db.orders.c.customer_id] else "-"
                 ),
 
                 # Tapahtuma
@@ -950,7 +1006,7 @@
                 tags.td(
                     tags.a(href='#')(
                         row[db.contacts.c.name]
-                    ) if row[db.orders.c.contact] else "-"
+                    ) if row[db.orders.c.contact_id] else "-"
                 ),
 
                 # Ajankohta
@@ -1023,47 +1079,53 @@
         Render form for database object, let the user make updates, update the database.
     """
     
-    def update (self, id, form) :
-        """
-            Update database values from form
+    def update (self, order, form) :
         """
-
-        sql = db.orders.update().where((db.orders.c.id == id)).values(
-            {
-                db.orders.c.customer            : form.customer_id,
-                db.orders.c.contact             : form.contact_id,
-                db.orders.c.event_name          : form.event_name,
-                db.orders.c.event_description   : form.event_description,
-                db.orders.c.event_start         : form.event_start,
-                db.orders.c.event_end           : form.event_end,
-            }
-        )
-
-        # execute it
-        self.app.execute(sql)
+            Update order values from submitted form data
+        """
+        
+        # modify
+        order.customer_id       = form.customer_id
+        order.contact_id        = form.contact_id
+        order.event_name        = form.event_name
+        order.event_description = form.event_description
+        order.event_start       = form.event_start
+        order.event_end         = form.event_end
+        
+        # commit
+        self.session.commit()
 
     def process (self, id) :
         """
-            Set up our form.
+            Set up our object form.
+
+            Process incoming POST data.
         """
 
+        # db session
+        self.session = self.app.session()
+        
+        # order object
+        self.order = self.session.query(Order).get(id)
+
+        # form
         self.form = OrderForm(self.app)
 
-        # use either POST data or database data
+        # load object data
+        self.form.load(id)
+        
+        # update order?
         if self.POST :
+
             # feed form our POST data
             if self.form.process(self.POST) :
-                # submit data OK
-                self.update(id, self.form)
+                # submit data was OK, update order from form
+                self.update(self.order, self.form)
 
             else :
                 # errors
                 pass
         
-        else :
-            # fetch data from database
-            self.form.load(id)
-
     def render_contract_form (self, id) :
         """
             Render the contract panel for our view
@@ -1104,22 +1166,27 @@
             Create the new order from the given form data, returning the new order's ID
         """
 
-        # if we've gotten this far, then we can create it!
-        sql = db.insert(db.orders).values(
-            customer            = form.customer_id,
-            contact             = form.contact_id,
-            
-            event_name          = form.event_name,
-            event_description   = form.event_description,
-            event_start         = form.event_start,
-            event_end           = form.event_end,
-        )
+        # db session
+        session = self.app.session()
 
-        # go!
-        order_id, = self.app.insert(sql)
+        # order model
+        order = Order()
 
-        # great
-        return order_id
+        # set attrs
+        order.customer_id           = form.customer_id
+        order.contact_id            = form.contact_id
+
+        order.event_name            = form.event_name
+        order.event_description     = form.event_description
+        order.event_start           = form.event_start
+        order.event_end             = form.event_end
+
+        # add and commit
+        session.add(order)
+        session.commit()
+
+        # return with new id
+        return order.id
 
     def process (self) :
         """