[Zope] PSQLINPUT Wizard Error

Zope zope@philosoft.at
Wed, 6 Oct 1999 13:29:31 +0200


This is a multi-part message in MIME format.

------=_NextPart_000_000E_01BF0FFE.D2931E70
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

I had the same error, but I could fix it:

1. open the file Zope\lib\python\Products\PSQLInput\Wizard.py
2. goto line 357, containing the following:
 self.aq_parent.manage_addZSQLMethod(sqlId, sqlTitle,
         self.connection_id,
         args, command)

3. replace the previous statement by the following:
self.aq_parent._setObject(sqlId, Products.ZSQLMethods.SQL.SQL(sqlId,
sqlTitle,
    self.connection_id, args, command))

4. restart Zope


I attached the complete Wizard.py

hope it helped

phil

----- Original Message -----
From: Ping Lau
To: zope@zope.org
Sent: Sunday, October 03, 1999 8:40 AM
Subject: [Zope] PSQLINPUT Wizard Error


Has anyone successfully used PSQLInput Product?  It gave me the error:
Error Type: AttributeError
Error Value: manage_addZSQLMethod
I am running Zope 2.0.1 & MySQL on Win98.
Regards,
Ping

------=_NextPart_000_000E_01BF0FFE.D2931E70
Content-Type: application/octet-stream;
	name="Wizard.py"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="Wizard.py"

"""P SQL Input Wizard

Help to create method, form and result page to insert data in a =
database.

This is a wizard to help create database input forms and SQL methods.=20
The idea is to help the user to select the database tables and columns =
to=20
which input data and the wizard automagically creates the insert SQL=20
method and the HTML input form.

You'll probably have to edit the generated documents and method. The =
method=20
specially if you are inputing data in multiple tables, since you'll want =
to=20
have the same data in multiple dates (e.g. person_id).
Remember that it is easier to take out paramenters than to search your=20
documentation/database for them, so don't be shy selecting items.

This software is released under GNU public license. See details in the =
URL:
http://www.gnu.org/copyleft/gpl.html

Author: Paulo Eduardo Neves <neves@inf.puc-rio.br>

Please send me bugs and feedback about how to improve it.
"""
import string
import Acquisition
from Globals import HTMLFile, Persistent, MessageDialog
import Products.ZSQLMethods.SQL


def implementedSQLConnectionIDs(self):
    """Find SQL database connections in the current folder and above

    This function return a list of ids.
    Shameless stolen (with little modifications) from SQL.py
    """
    ids=3D{}
    have_id=3Dids.has_key
    StringType=3Dtype('')

    while self is not None:
        if hasattr(self, 'objectValues'):
            for o in self.objectValues():
		try:
		    if (hasattr(o,'_isAnSQLConnection')=20
			and o._isAnSQLConnection
			and hasattr(o,'id')):
			#let's see if this DB is suported
			if not hasattr(o, 'database_type'):
			    raise ImportError
			exec('import DBInfo.' + getattr(o, 'database_type'))
		=09
			id=3Do.id
			if type(id) is not StringType: id=3Did()
			if not have_id(id):
			    if hasattr(o,'title_and_id'): o=3Do.title_and_id()
			    else: o=3Did
			    ids[id]=3Did
		except ImportError:
		    #Database is not supported
		    pass=20
        if hasattr(self, 'aq_parent'): self=3Dself.aq_parent
        else: self=3DNone

    ids=3Dmap(lambda item: (item[1], item[0]), ids.items())
    ids.sort()
    return ids

manage_startWizard =3D HTMLFile('selectDB', globals())

def _generateId(self, baseName):
    "Returns a not used attribute in the self object"
    id =3D baseName
    count =3D 1
    while hasattr(self, id):
	id =3D baseName + `count`
	count =3D count + 1
    return id

def debug(self):
    "debug"
    return ""

def manage_createWizard(self, connection_id, REQUEST):
    """Create the wizard for the desired connection_id
       and call it's default method """

    id =3D _generateId(self, "psqlwiz") #default name
    wiz =3D PSQLInputWizard(id, connection_id)
    setattr(self, id, wiz)

    REQUEST.RESPONSE.redirect("%s/%s" % (REQUEST['URL1'], id))

class Table:
    """Class to group table and columns atributtes

    Just to have a cleaner (dtml) code"""
    def __init__(self, name, columns, optionalColumns =3D []):
	self.tableName =3D name
	self.columns =3D columns
	self.optional =3D optionalColumns
=09
    def __str__(self):
	return "Table Name:%s<BR>\nColumns:%s" % (self.tableName, =
`self.columns`)

class PSQLInputWizard(
    Acquisition.Implicit,
    Persistent,
    ):
    """A Wizard to create  forms and methods to insert data in databases

    The wizard uses a sequence of forms to ask the user for data,
    these data are stored as attributes in the wizard. When all the =
necessary=20
    data are gathered it creates the input form, result page and method.
    """


    __ac_permissions__ =3D (
	('Use SQL Wizard', ('index_html', 'collectIds',=20
			    'selectColumns', 'getObjectsInfo',
			    'createSQLInput', 'quit')),
	)
    meta_type =3D 'P SQL Input Wizard'



    dtmlDir =3D 'Products/PSQLInput/'

    def __init__(self, id, connection_id):
	self.id =3D id
	self.connection_id =3D connection_id
	self.tables =3D []
	self.selectedTables =3D []
	self.tableColumns =3D []
	self.selectedColumns =3D []
	self.sqlArguments =3D []



    def _infoFactory(self):
	connection =3D getattr(self, self.connection_id)
	exec('import DBInfo.' + connection.database_type)
	return eval('DBInfo.' + connection.database_type + '.Info(connection)')

    def index_html(self):
	"Start input wizard data gathering, show database tables to the user"

	self.info =3D self._infoFactory()
	self.tables =3D self.info.getTablesNames()=20

	selectTables =3D HTMLFile( self.dtmlDir + 'selectTables')
	return selectTables(self, self)


    def queryColumns(self,  selectedTables =3D []):
	"Ask user to select data columns in selected tables"

	if selectedTables !=3D []:
	    self.selectedTables =3D []
	    for i in selectedTables:
		self.selectedTables.append(self.tables[i])

	    self.tableColumns =3D []
	    for i, j in self.info.getColumnsNames(self.selectedTables).items():
		self.tableColumns.append(Table(i,j))

	selectColumns =3D HTMLFile(self.dtmlDir + 'selectColumns')
	return selectColumns(self,self)
=09
   =20
    def _cleanColName(self, name):
	return string.join(map(string.capitalize, string.split(name, '_')))
   =20
    def _uniqueCol(self, table, column):
	#return table + string.capitalize(column)
	return table + '.' + column
=20
    def _buildInputForm(self, resultPageId):
	#base %s parameters: result page id, form contents
	base =3D """<!--#var standard_html_header-->
<H2><!--#var title_or_id--> <!--#var document_title--></H2>
<P><FORM ACTION=3D"%s" METHOD=3D"POST">
<TABLE>
%s
</TABLE>
<input type=3D"SUBMIT" name=3D"submit" value=3D"Insert">
</FORM>
<!--#var standard_html_footer-->"""
        inputBase =3D '\t<TR><TD ALIGN=3D"RIGHT">%s</TD><TD><INPUT =
TYPE=3D"TEXT" NAME=3D"%s"></TD></TR>'
	form =3D []
	for i in self.selectedColumns:
	    form.append('<TR BGCOLOR=3D"#CCCCCC"><TD COLSPAN=3D2>%s</TD></TR>'=20
			% i.tableName)
	    for j in i.columns:
		if j in i.optional:
		    form.append(inputBase=20
				% (self._cleanColName(j),=20
				   self._uniqueCol(i.tableName, j)))
		else:
		    form.append(inputBase=20
				% ("<B>" + self._cleanColName(j) + "</B>",=20
				   self._uniqueCol(i.tableName, j)))


	return base % (resultPageId, string.join(form, '\n'))

    def _buildResultPage(self, sqlMethodId):
	base =3D """<!--#var standard_html_header-->
<H2><!--#var title_or_id--> <!--#var document_title--></H2>
<P><!--#call "%s(REQUEST)"-->
Your data was inserted in the Database!
<!--#var standard_html_footer-->""" # How do I catch SQL errors?
        return base % sqlMethodId

    def debug(self):
	"sss"
	x =3D ''
	for i in table.columns: x=3D x+ ' ' + i
	x =3D x+ '\n************\n'
	for i in table.optional: x=3D x+ ' ' + i
	return x

    def _buildSQLValues(self, table, nonOptCol):
	template =3D '<!--#sqlvar %s type=3D%s %s-->'
	args =3D []
	for i in table.columns:
	    tp =3D self.info.type(table.tableName, i)
	    opt =3D self.info.nullable(table.tableName, i)
	    uniqueCol =3D self._uniqueCol(table.tableName, i)
	   =20
	    oneArg =3D template % (uniqueCol, tp, opt) + ','
	    if i in table.optional:
		args.append('<!--#if %s-->\n\t\t\t%s\n\t\t<!--#/if-->'
			    % (uniqueCol, oneArg))
	    else:
		args.append(oneArg)

	#there's just missing the non optional (without the comma)
	tp =3D self.info.type(table.tableName, nonOptCol)
	opt =3D self.info.nullable(table.tableName, nonOptCol)
	uniqueCol =3D self._uniqueCol(table.tableName, nonOptCol)
	args.append(template % (uniqueCol, tp, opt))

	return string.join(args, '\n\t\t')

    def _buildSQLInto(self, table, nonOptCol):
	tempCols =3D []
	for i in table.columns:
	    tempCols.append(i + ',')

	newCol =3D []
	for i in range(len(table.columns)):
	    if  table.columns[i] in table.optional:
		newCol.append('<!--#if %s -->\n\t\t%s\n\t<!--#/if-->' %=20
			      (self._uniqueCol(table.tableName,
					       table.columns[i]),=20
			       tempCols[i]))
	    else:
		newCol.append(tempCols[i])

	newCol.append(nonOptCol)
	return string.join(newCol,'\n\t')
=09
    def _buildSQLInputCommand(self):
	baseCommand =3D "INSERT INTO %s \n\t(%s)\n\tVALUES (%s)"
	command =3D []
	inputArgs =3D []

	for i in self.selectedColumns:
	    #building sql method arguments
	    for j in i.columns:
		tempArg =3D self._uniqueCol(i.tableName, j)
		if j in i.optional:
		    tempArg =3D tempArg + '=3D""'
		inputArgs.append(tempArg)

	    #Let's find a column that isn't optional,=20
	    #I've already verified in getObjectsInfo that it exists
	    for col in i.columns:
		if col not in i.optional:
		    nonOptCol =3D col
		    i.columns.remove(col)
		    break

	    #building sql method
	    command.append(baseCommand % (i.tableName,=20
					  self._buildSQLInto(i, nonOptCol),
					  self._buildSQLValues(i, nonOptCol)))

	return string.join(inputArgs), string.join(command,'\n<!--#var =
sql_delimiter -->\n')


    def getObjectsInfo(self, REQUEST):
	"Store data and Collect id's and title of objects to be created"
	self.selectedColumns =3D []
	for i in self.selectedTables:
	    if REQUEST.has_key(i):
		optional =3D []
		if REQUEST.has_key('opt.' + i):
		    optional =3D REQUEST['opt.' + i]

		oneColNonOptional =3D None
		for j in REQUEST[i]:
		    if j not in optional:
			oneColNonOptional =3D 1
			break
		if oneColNonOptional is None:
		    return MessageDialog(title=3D"Error",
					 message =3D "<h1>Error</h1>There must be at least one selected =
non-optional column",
					 action =3D REQUEST['HTTP_REFERER']
					 )
	=09
		self.selectedColumns.append(Table(i, REQUEST[i],=20
						  optional))

	if self.selectedColumns =3D=3D []:
	    return MessageDialog(title=3D"Error",
				 message =3D "<h1>Error</h1>You Must select at least one column of =
one table",
				 action =3D REQUEST['HTTP_REFERER']
				 )

	allTables =3D string.join(map(string.capitalize, =
self.selectedTables),'')
	defaultTitles =3D string.join(map(string.capitalize,=20
					self.selectedTables))
	formDefaultId =3D _generateId(self.aq_parent, allTables + "InsertForm")
	resultDefaultId =3D _generateId(self.aq_parent,=20
				      allTables + "InsertResult")
	sqlMethodDefaultId =3D _generateId(self.aq_parent,=20
					 allTables + "InsertMethod")

	collectIds =3D HTMLFile(self.dtmlDir + 'collectIds')
	return  collectIds(self,=20
			   formId=3DformDefaultId,=20
			   resultId=3DresultDefaultId,
			   sqlId=3DsqlMethodDefaultId,
			   titles=3DdefaultTitles)
   =20
    def createSQLInput(self, RESPONSE, URL2, formId, resultId, sqlId,=20
		       formTitle=3D'', resultTitle =3D '', sqlTitle =3D ''):
	"""Method to add the Z SQL Method and a Form to access it,=20
	also delete Wizard from parent folder """

	try:
	    self.aq_parent.manage_addDTMLDocument(formId, formTitle,=20
						  self._buildInputForm(resultId) )=20
	except AttributeError:
	    self.aq_parent.manage_addDocument(formId, formTitle,=20
						  self._buildInputForm(resultId) )=20

	try:
	    self.aq_parent.manage_addDTMLDocument(resultId, resultTitle,=20
						  self._buildResultPage(sqlId) )=20
	except AttributeError:
	    self.aq_parent.manage_addDocument(resultId, resultTitle,=20
						  self._buildResultPage(sqlId) )=20
	   =20

	args, command =3D self._buildSQLInputCommand()
	#self.aq_parent.manage_addZSQLMethod(sqlId, sqlTitle,=20
	#				    self.connection_id,
	#				    args, command)

	#corrected by Philosoft Okt 1,1999:
	self.aq_parent._setObject(sqlId, Products.ZSQLMethods.SQL.SQL(sqlId, =
sqlTitle,
		self.connection_id, args, command))

	self.quit(RESPONSE, URL2)

    def quit(self, RESPONSE, URL2):
	"Cleans temporary objects used by P SQL Wizard"
=09
	delattr(self.aq_parent, self.id) #deleting wizard, if you leave in the =
middle there will be trash in your folder
=09
=09
	RESPONSE.redirect(URL2 + '/manage_main') #should I show some message?


   =20


------=_NextPart_000_000E_01BF0FFE.D2931E70--