[Zope3-Users] formlib with no zodb

Maciej Wisniowski maciej.wisniowski at coig.katowice.pl
Fri Mar 16 05:36:48 EDT 2007


> Is it possible to build a page with formlib, widgets, and a page
> template without using the ZODB or ZMI.  I have been trying for awhile
> to accomplish this with no luck.  I want to build an edit form that
> shows results from a postgresql database which does not add any
> objects within the zodb.  If anyone can help or has any examples I
> would really appreciate it.
Recently I started to write real application that uses my
product for RDBMS interaction (I've sent you links to
very first (and very unstable) version of this). 
Because of doing real work I did some fixes and changes to
my general product. I called this 'dbformlib'. First stable version
is available at:
http://dbcrudbase.googlecode.com/svn/tags/dbformlib_1_0/
I know that you may hate this product already because of it's
recent unstability (but it was still developement)
but if you want to give it second try then take a look at it now.

In general it is supposed to create one content object
that is a gateway between user and RDBMS. Each content object
handles one(!) form (but a lot of rows from database).
Eg. you have table Account in RDBMS
so you will create 'account_content object' that will have
few SQLScripts inside to call: select, update, insert, delete
statements on Account table.
Then you will create views for edit, add, delete (just like in formlib).

Only difference is that for forms other than 'add' you need row id
to know which row should be returned from database.
row 'id' is called Entry parameter by me, because it has to
appear in request like:

http://localhost/mysite/mycontentobj/edit.html?in.id=1

thanks to this, your's select can be like:
select * from Account where id=<dtml-sqlvar id type="int">

Simple usage may be seen at application located at:
docs/sample but this doesn't use real database.
Description is at docs/sample/Readme.txt.

Below some code from my real app that uses dbformlib.
One important thing is connectionName. You have to
create (and register at your site) database adapter.
It's name is then used as 'connectionName'.
In my case I have site that during add, creates my content
and sets connectionName but you may use hardcoded value
instead of self.Connection while creating SQLScripts.

For a start you may take 'Sample DBFormlib' application and create
some SQLMethods in it and just call them with hardcoded
'connectionname'.


interfaces.py
-----------------------
from zope.schema import TextLine, URI

from dbformlib.fields import EntryField
from dbformlib.interfaces import IDBFormlibContent

class IAccount(IDBFormlibContent):
    """ Content object interface
    """
    id         = EntryField(title=u"id")
    cancel_url = EntryField(title=u"cancel_url", required=False)
    aplikacja  = TextLine(title=u"Aplikacja")
    adres      = URI(title=u"Adres")


mycontent.py
-----------------------
from dbformlib.dbformlib import DBFormlibContent
from interfaces import IAccount

class Account(DBFormlibContent):
    zope.interface.implements(IMonitorConfDB)

    def setup(self):
        # select
        sql = 'select * from monitor_conf where id=<dtml-sqlvar id
type="int">'
        sqlArguments = 'id'
        sqlQuery = SQLScript(self.connectionName, sql, sqlArguments)
        self['get_config_entry'] = sqlQuery
        notify(ObjectCreatedEvent(sqlQuery))
               
        # update
        sql ='''update monitor_conf set
                       aplikacja=<dtml-sqlvar aplikacja
type="string">,                     
                       adres=<dtml-sqlvar adres type="string">
                where id=<dtml-sqlvar id type="int">'''
        sqlArguments = 'id aplikacja adres'
        sqlQuery = SQLScript(self.connectionName, sql, sqlArguments)
        self['set_config_entry'] = sqlQuery
        notify(ObjectCreatedEvent(sqlQuery))      
               
    def _get_form_data(self, crud_id, in_params={}):
        ret_dict={}
        if crud_id=='edit':
            try:
                res = self['get_config_entry'](id=in_params['id'])
                if res:
                    ret_dict['aplikacja']=res[0].APLIKACJA
                    ret_dict['adres']=res[0].ADRES
                    return ret_dict
                raise UserError('No data for this ID!')
            except DatabaseException, err:
                raise UserError(u'DB error')          
        else:
            return {'adres':'http://'}
 
    def _set_form_data(self, crud_id, data, errors=[]):
        try:
            if crud_id=='edit':           
                self['set_config_entry'](id=data['id'],
                                      aplikacja=data['aplikacja'],
                                      adres=data['adres'])
        except DatabaseException, err:
            errors.append(u'db error...')


views.py
---------------
from zope.formlib import form
from zope.app.form.browser import BytesWidget
from zope.traversing.browser.absoluteurl import absoluteURL
from dbformlib.browser import DBFormlibEditForm
from monitor.interfaces import IAccount

class WideBytesWidget(BytesWidget):
    displayWidth = 80

class AccountEditForm(DBFormlibEditForm):
    label   = u'Edit my data'
    actions = DBFormlibEditForm.actions
    
    def define_fields(self):        
        self.form_fields = form.Fields(IAccount)
        self.form_fields['adres'].custom_widget = WideBytesWidget
    
    @form.action(u'Cancel', validator=lambda *a: ())  # hack to omit
validation
    def handle_cancel_action(self, action, data):
        data = self.get_data_obj().get_data()
        absoluteURL(self.context, self.request)
        
        if data['cancel_url']:
            self.request.response.redirect(data['cancel_url'])
        return None


configure.zcml
-------------------------
...
<browser:page
      name="edit.html"
      for="..interfaces.IAccount"
      class=".views.AccountEditForm"
      permission="zope.View"
      />
...

-- 
Maciej Wisniowski


More information about the Zope3-users mailing list