This is installment two of the bizObject tutorial. But before we can continue
we need to setup two tables and add data to the tables. I am providing
standard “Postgres” SQL statements that will create the tables and insert the
data we will be working with though out the tutorial. However, each database
engine has it own sightly different SQL syntax. Therefore, pay close
attention to fact that I have constraints on the tables and that both tables
have primary keys. The primary fields are auto-increment and I force the
custno field to be unique using a constraint. So if you are not using
Postgres you will have to create your own SQL statements to setup the tables
and enter the data. We will not be using any store procedures/functions or
anything else the database engine has available. After all this is about
Dabo and not Postgres. However, you can count on Dabo allowing your
database to be all it can be!
-- drop table arcustomer;
CREATE TABLE arcustomer
(custno character varying(15) NOT NULL,
company character varying(35),
address1 character varying(35),
address2 character varying(35),
city character varying(35),
state character varying(2),
country character varying(60),
czip character varying(10),
pkid serial NOT NULL,
CONSTRAINT pk_arcust PRIMARY KEY (pkid),
CONSTRAINT arcustno UNIQUE (custno)
)
WITHOUT OIDS;
ALTER TABLE arcustomer OWNER TO johnf;
GRANT ALL ON TABLE arcustomer TO johnf;
--DROP TABLE contacts;
CREATE TABLE contacts
(
custno character varying(15) NOT NULL,
firstname character varying(20),
lastname character varying(35),
title character varying(20),
phone character varying(15),
email character varying(40),
continent character varying(35),
cont_note text,
pkid serial NOT NULL,
fk_arcust integer,
CONSTRAINT pk_contact PRIMARY KEY (pkid)
)
WITHOUT OIDS;
ALTER TABLE contacts OWNER TO johnf;
GRANT ALL ON TABLE contacts TO johnf;
insert into arcustomer
(custno,company,address1,address2,city,state,country,czip)
values('AAA','AAA company', '123 Main
St.','','Wooland','CA','USA','95776');
insert into arcustomer
(custno,company,address1,address2,city,state,country,czip)
values('BBB','BBB company', '123 East St.','Apt
2','Wooland','CA','USA','95776');
insert into arcustomer
(custno,company,address1,address2,city,state,country,czip)
values('CCC','CCC company', '123 Walker
St.','','Wooland','CA','USA','95776');
insert into contacts
(custno,firstname,lastname,title,phone,email,continent,fk_arcust)
values('AAA', 'Ed', 'Leafe', 'Mr.', '','[EMAIL PROTECTED]','North
America',1);
insert into contacts
(custno,firstname,lastname,title,phone,email,continent,fk_arcust)
values('BBB', 'Paul', 'McNet', 'Mr.', '','[EMAIL PROTECTED]','North
America',2);
insert into contacts
(custno,firstname,lastname,title,phone,email,continent,fk_arcust)
values('CCC', 'Larry', 'Long', 'Mr.', '','[EMAIL PROTECTED]','North
America',3);
OK we got the data into the tables. Now we need to add a real bizObject to
our form. I like to think of myself as programmer (note: others might not
agree with that label). So I'm lazy! Instead of typing the required code I
use a short cut – ClassDesigner! That's right, the guy (me) that hand codes
the UI uses the ClassDesigner. We are going to let ClassDesigner write our
bizObject class code for us!
Open the ClassDesigner and right click on the form (window Title is “Dabo
Class Designer”) and select the “Add Controls from Data environment”. Select
your connection file, and then select one of our tables (arcustomer or
contacts). Continue the process by selecting all the fields (click on Select
all). Click next. And continue to click next until you get to the “BizObj
Code” screen and make sure you have checked the “Add BizObj Code”. Then
click on the “Finish” button. Like magic the code we need will appear in
the “ClassDesigner” editor. Should look something like:
class PubliccontactsBizobj(dabo.biz.dBizobj):
def afterInit(self):
self.DataSource = "public.contacts"
self.KeyField = "pkid"
self.addFrom("public.contacts")
self.addField("fk_arcust")
self.addField("firstname")
self.addField("title")
self.addField("pkid")
self.addField("lastname")
self.addField("cont_note")
self.addField("continent")
self.addField("phone")
self.addField("custno")
self.addField("email")
...
The ClassDesigner has created a class, named the class and added all the
fields in our table to the class. Like I said - Magic. I'm sure you are
wondering what's up with the word “public” in "public.contacts". Postgres
has the concept of “schema” and Dabo of course supports schema's. If you are
not using Postgres and don't know anything about Postgres schema's don't
worry about it. If you followed my instructions the ClassDesigner will
provide with the correct naming of the “DataSource”.
DataSource of course is the name of our table. The “self.addFrom” will
normally match the DataSource and is used to provide the “from” in the SQL
statement as in:
Select * “From public.contacts”. And of course the “self.addField” statements
add the names of the fields from our table. But I skipped over
the “self.Keyfield”?
“self.Keyfield” is the name of the primary field of the table. Yes, Dabo
supports compound keys. There has been plenty of discussion on what Dabo
should or should not do in support of primary keys. If you are interested
you can check out the Dabo list archive. For the purposes of this tutorial
we are using an auto-increment key provided by the database engine. BTW with
respect to Postgres users ALL tables are required to have a primary key.
That fact is not because I was trying to force my ideas on Dabo users (I
wrote most of the dbPostgres.py interface) although I believe all tables
should have PK's. It was because I could not find a way to provide table
security based on user name without having a PK for each table. We are
building a one to many application and Dabo requires that a PK be provided so
that the child relation can be maintained. So if we want to use the power of
Dabo we need PK's.
Next, ClassDesigner provided the code for an empty validator (is that a
word?):
def validateRecord(self):
"""Returning anything other than an empty string from
this method will prevent the data from being saved.
"""
ret = ""
# Add your business rules here.
return ret
Last, we have the code to create an instance of our bizObject class:
publiccontactsBizobj = PubliccontactsBizobj(self.Connection)
self.addBizobj(publiccontactsBizobj)
OK so where do we put all this code? Simple, the “class” is of course a
class. We add it to our code like any other class. Below in our code I
added the class at the top. But where does the code to create the instance
of class go? In the “createBizobjs” method! In Dabo the “app.start()” will
execute the “createBizobjs” method and therefore create an instance of our
class – create the object we will use. A bizObject!
To add the second table I just repeat what I did to add the first table.
Below I have created a small application. I hate the UI in this example. So
would some kind reader post a better UI. The code creates a one to many
relation between a customer table and the customer contacts table. I have
added several buttons and extra lines to create the child relation and we
will go over that code in the next installment. So far all we have done is
discuss the connection and added a bizObject to our code. Next time we will
discuss what steps I took to create the child relation and what Dabo provides
to help the developer pass SQL statements to the database engine.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import dabo
import dabo.dEvents as dEvents
import dabo.dException as dException
dabo.ui.loadUI('wx')
#the contact table
class PubliccontactsBizobj(dabo.biz.dBizobj):
def afterInit(self):
self.DataSource = "public.contacts"
self.KeyField = "pkid"
self.addFrom("public.contacts")
self.addField("firstname")
self.addField("phone")
self.addField("pkid")
self.addField("lastname")
self.addField("title")
self.addField("custno")
self.addField("continent")
self.addField("email")
self.addField("cont_note")
self.addField("fk_arcust")
self.NonUpdateFields=["pkid"]
self.LinkField = "fk_arcust"
self.ParentLinkField ="pkid"
self.FillLinkFromParent = True
def validateRecord(self):
"""Returning anything other than an empty string from
this method will prevent the data from being saved.
"""
ret = ""
# Add your business rules here.
return ret
#the customer table
class PublicarcustBizobj(dabo.biz.dBizobj):
def afterInit(self):
self.DataSource = "public.arcustomer"
self.addFrom("public.arcustomer")
self.KeyField = "pkid"
self.addField("czip")
self.addField("city")
self.addField("pkid")
self.addField("state")
self.addField("company")
self.addField("address1")
self.addField("address2")
self.addField("country")
self.addField("custno")
def validateRecord(self):
"""Returning anything other than an empty string from
this method will prevent the data from being saved.
"""
ret = ""
# Add your business rules here.
return ret
class CustomerPanel(dabo.ui.dPanel):
def afterInit(self):
self.Sizer=vs=dabo.ui.dSizer('h')
gs = dabo.ui.dGridSizer(MaxCols=4,HGap=3, VGap=3)
gs.append(dabo.ui.dLabel(self, Caption="Cust #"),
halign="right")
gs.append(dabo.ui.dTextBox(self,
RegID="txtCustomerID",TextLength =
10,DataSource ="public.arcustomer", DataField = "custno"), "expand",
colSpan=3)
gs.append(dabo.ui.dLabel(self, Caption="Address"),
halign="right")
gs.append(dabo.ui.dTextBox(self, RegID="txtAddress1",TextLength
=
35,DataSource ="public.arcustomer", DataField = "address1"), "expand",
colSpan=3)
gs.append(dabo.ui.dLabel(self, Caption=""), halign="right")
gs.append(dabo.ui.dTextBox(self, RegID="txtAddress2",TextLength
=
35,DataSource ="public.arcustomert", DataField = "address2"), "expand",
colSpan=3)
gs.append(dabo.ui.dLabel(self, Caption="City"), halign="right")
gs.append(dabo.ui.dTextBox(self, RegID="txtCity",DataSource
="public.arcustomer", DataField = "city"), "expand", colSpan=3)
gs.append(dabo.ui.dLabel(self, Caption="Country"),
halign="right")
gs.append(dabo.ui.dTextBox(self, RegID="txtCountry1",DataSource
="public.arcust", DataField = "country"), "expand", colSpan=3)
gs.append(dabo.ui.dLabel(self, Caption="State"), halign="right")
gs.append(dabo.ui.dTextBox(self,
RegID="txtSateID",ForceCase='upper',TextLength=2,DataSource
="public.arcustomer", DataField = "state"))
gs.append(dabo.ui.dLabel(self, Caption="Zip"), halign="right")
gs.append(dabo.ui.dTextBox(self,
RegID="txtZipD",TextLength=10,DataSource
="public.arcustomer", DataField = "czip"), "expand")
vs.append(gs,0,'x')
class ContactsPanel(dabo.ui.dPanel):
def afterInit(self):
self.Sizer = dabo.ui.dSizer("v")
hs=dabo.ui.dSizer("h")
contactGrid =
dabo.ui.dGrid(self,RegID="contgridID",AlternateRowColoring
=True,ColumnCount=6,SelectionMode = "Row",Editable = True,MovableColumns =
False)
#self.contactGrid.bindEvent(dabo.dEvents.GridCellSelected,self.onGridCellSelected)
contactGrid.DataSource = "public.contacts"
contactGrid.Columns[0].Caption ="Title"
contactGrid.Columns[0].DataField = "title"
contactGrid.Columns[1].Caption ="First"
contactGrid.Columns[1].DataField = "firstname"
contactGrid.Columns[2].Caption ="Last"
contactGrid.Columns[2].DataField = "lastname"
contactGrid.Columns[3].Caption ="Email"
contactGrid.Columns[3].DataField = "email"
contactGrid.Columns[4].Caption ="Phone"
contactGrid.Columns[4].DataField = "phone"
contactGrid.Columns[5].Caption ="Continent"
contactGrid.Columns[5].DataField = "continent"
hs.append(contactGrid,1,'x')
self.Sizer.append(hs,1,'x')
class MainForm(dabo.ui.dForm):
def afterInit(self):
self.Sizer=vs=dabo.ui.dSizer('v')
custPanel=CustomerPanel(self)
vs.append(custPanel,1,'x')
vs.appendSpacer(8)
hs= dabo.ui.dSizer('h')
hs.append(dabo.ui.dButton(self,
Caption="First",OnHit=self.first),0)
hs.append(dabo.ui.dButton(self,
Caption="Next",OnHit=self.next),0)
hs.append(dabo.ui.dButton(self,
Caption="Prior",OnHit=self.prior),0)
hs.append(dabo.ui.dButton(self,
Caption="Last",OnHit=self.last),0)
vs.append(hs)
vs.appendSpacer(8)
contPanel=ContactsPanel(self)
vs.append(contPanel,2,'x')
self.layout()
self. requery()
def first(self,evt):
self.super()
def next(self,evt):
self.super()
def prior(self,evt):
self.super()
def last(self,evt):
self.super()
def createBizobjs(self):
self.Application.addConnectFile("tutorial.cnxml")
self.Connection =
self.Application.getConnectionByName("tutorial")
publicarcustBizobj = PublicarcustBizobj(self.Connection)
self.addBizobj(publicarcustBizobj)
publiccontactsBizobj = PubliccontactsBizobj(self.Connection)
self.addBizobj(publiccontactsBizobj)
publicarcustBizobj.addChild(publiccontactsBizobj)
if __name__ == "__main__":
app = dabo.dApp()
app.BasePrefKey = "bizObjTutor"
app.setAppInfo("appName", "bizObject Tutorial ")
app.MainFormClass = MainForm
app.start()
As always if I have errors point them out. Better yet provide the fix.
--
John Fabiani
_______________________________________________
Post Messages to: [email protected]
Subscription Maintenance: http://leafe.com/mailman/listinfo/dabo-users
Searchable Archives: http://leafe.com/archives/search/dabo-users
This message: http://leafe.com/archives/byMID/dabo-users/[EMAIL PROTECTED]