''' 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.BackendName = "MySQL" # backend type (MySQL, MSSQL, Postgres...) self.Host = 'leafe.com' # host, (host.domain.com or ip address) self.DbName = "webtest" # database name to log in to self.User = "test" # user name self.Password = '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.czip.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") # This is where you can set the columns in the data source # which are displayed in the form, as well as what fields # are searchable. Try commenting/uncommenting the following # two sections to see the difference. # self.setColumnDefs(self.getBizobj().DataSource, # [{'tableName': 'zipcodes', 'fieldName': 'czip', # 'caption': 'Zip Code', 'type': 'C', 'selectTypes':['range',]}, # {'tableName': 'zipcodes', 'fieldName': 'ccity', # 'caption': 'City', 'type': 'C'}]) self.setColumnDefs(self.getBizobj().DataSource, [ {'tableName': 'zipcodes', 'fieldName': 'ccity', 'caption': 'City', 'type': 'C', 'selectTypes': ['stringMatch', 'stringMatchAll']}, {'tableName': 'zipcodes', 'fieldName': 'cstateprov', 'caption': 'State/Prov', 'type': 'C', 'selectTypes': ['stringMatch']}, {'tableName': 'zipcodes', 'fieldName': 'czip', 'caption': 'Zip Code', 'type': 'C', 'selectTypes':['range',]}, {'tableName': 'zipcodes', 'fieldName': 'ccounty', 'caption': 'County', 'type': 'C', 'selectTypes': ['stringMatch']}, ]) def instantiateBizobj(self): self.addBizobj(MyBizobj(self._connection)) def OnClose(self, event): MyForm.doDefault(event) # Close the main frame as well for this simple demo: wx.GetApp().GetTopWindow().Close(True) event.Skip() # 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