''' SimpleFormWithBizobj.py This demo shows a subclass of dForm populated by dControl instances. The dForm is attached to a dBizobj, which is attached to a dCursor, which is "attached" to a MySQLdb backend. Each dControl has its dataSource and dataField properties set appropriately, so the control's value reflects the current value in the cursor. Requires: dabo wx MySQLdb unblocked Internet connection on port 3306 to leafe.com ''' import wx from dabo import * from dabo.ui import * from dabo.biz import * from dabo.db import * from dabo.dLocalize import _ import dabo.dException as dException # Dabo is a 3-tier application framework, which means that there is a # database tier, a business object tier, and a user-interface tier. This # demo instantiates the Dabo application object which holds all these # tiers together, but before that can happen we must subclass the relevant # base classes in each of the tiers. Follow along with the subclasses. # We start with the database, followed by the bizobj and the ui. # DB tier: # There isn't much to do here except define some connection information # parameters. When the form instantiates the bizobj, it'll first instantiate # a dConnection object, which gets created using the connect info defined # here. class MyConnectInfo(dConnectInfo): def __init__(self): dConnectInfo.__init__(self) self.setBackendName("MySQL") # backend type (MySQL, MSSQL, Postgres...) self.setHost('leafe.com') # host, (host.domain.com or ip address) self.setDbName("webtest") # database name to log in to self.setUser("test") # user name self.setPassword('test3') # user's password # Bizobj tier: # For this demo, we define only one bizobj. class MyBizobj(dBizobj): # This is a subclass of dabo's dBizobj base class. Look how simple it # is to set up the required parameters. def beforeInit(self): self.DataSource = "zipcodes" # the 'alias' for the bizobj/cursor self.KeyField = "iid" # the primary key self.RequeryOnLoad = False # don't do an implicit requery on init # Set the default values for new records added defaultValues = {"ccity":"Penfield", "cstateprov":"NY", "czip":"14526"} def validateRecord(self): # Here are your business rules. We start with a pretty silly one, # and go from there. This is pretty easy stuff! # Initially set the error message to an empty string. If this method # makes it all the way through with no biz rule violations, the string will # still be empty and the bizobj will let the commit happen. errorText = "" # Biz rules follow. These can be as complex as necessary, the key # thing is to remember to add to the error message so the user knows # why a failure happened. You can also use the localization function # named _() around your text if you need to provide localized # messages. # Rules for ccity: if self.ccity.find("XX") >= 0: # We aren't allowing double X's in the city name, for some strange reason errorText += _("Cities may not have the letters 'XX' in them.\n") # Rules for czip: if len(self.czip.strip()) < 1: errorText += _("Zip code may not be blank.\n") if len(self.zip.strip()) > 5: errorText += _("Zip code must not be more than 5 characters long.\n") # Tell the bizobj if all rules passed or not. If the returned string # is empty, everything's fine, and the validation passes. return errorText # UI tier: # We subclass dabo.ui.dFormDataNav, which is a plain dForm with added # data navigation abilities. class MyForm(dFormDataNav): def afterInit(self): MyForm.doDefault() self.Name = "MyForm" self.Caption = "Zip Codes" self.Size = (400,280) self.Position = (40,60) self.debug = True # output verbose self._connection = dConnection(MyConnectInfo()) self.instantiateBizobj() self.getBizobj().setFieldClause("*") self.getBizobj().setFromClause("zipcodes") self.getBizobj().setGroupByClause("zipcodes.iid") self.setColumnDefs(self.getBizobj().DataSource, [{'tableName': 'zipcodes', 'fieldName': 'czip', 'caption': 'Zip Code', 'type': 'C', 'selectTypes':['range',]}, {'tableName': 'zipcodes', 'fieldName': 'ccity', 'caption': 'City', 'type': 'C'}]) def instantiateBizobj(self): self.addBizobj(MyBizobj(self._connection)) def OnClose(self, event): # Close the main frame as well for this simple demo: wx.GetApp().GetTopWindow().Close(True) # The code below will only get executed if this file is run as a script # versus imported as a module. This is how this demo is meant to be run, # but remember this Python 'feature' when developing your own subclasses: # it is great for setting up simple unit tests. if __name__ == "__main__": app = dApp() # instantiate dApp app.setup() # must be done before app.start() form = MyForm(app.uiApp.mainFrame) # instantiate the form form.Show(True) # show the form app.start() # start the app event loop