[Zope] skinscript and ZSQL
Steve Spicklemire
steve@spvi.com
Sun, 17 Dec 2000 05:33:21 -0500 (EST)
Hi Aaron,
Since we communicated privately and I now have a much better
understanding of your problem, I realized that my last message to the
list was unclear so I thought I'd take a moment to try to clarify the
'gotchas' that got you, as I see them, so that other folks might not
so easily fall into the same problems.
Since you started with "DumbZPatternsExample":http://www.zope.org/Members/sspickle/DumbZPatternsExample
others might be able to follow along better if they refer to that
example.
Situation:
You're creating a class that is used as a 'stand-in' for
objects stored in an SQL database. You're using ZPatterns to implement
this stand-in-ability.
These objects have the following attributes (these also correspond to
column names for the table that lives in the SQL database, in your
case, gadfly.)
client_name, email, rate, last_payment, primary, and services.
client_name is used as the 'id' of the object when it is
instantiated in Zope.
In order to accomplish this you:
1) Create a ZClass (ClientObject) to act as the stand-in.
1a) set up methods of the ZClass
editInstance: self.propertysheets.Basic.manage_changeProperties(REQUEST)
editInstanceForm: (form to edit the properties of an instance)
editInstanceInterface: (UI method that calls editInstance to get modification done)
index_html: (display this instance)
1b) set up propertysheet for ZClass
add properties: email, rate, last_payment, primary and services.
do *not* set up a property for client_name since it is really
going to be the 'id', and also the property that the rack uses to see
if the object was found in the database.
[ If 'client_name' were propertysheet-property then the Rack could
create a virtual instance, and then attemt to access the property
'client_name'. This would then fire the trigger that queries the
database, which would fail (leaving the virtual instance
unchanged). Since the virtual instance is an instance of your
ZClass even though the query failed the Rack would *still* get a
valid value for the property from the ZClass property sheet!
This is why you were getting the 'already exists' error in
the first place. Taking the 'client_name' property out of the
ZClass fixes this problem. ]
2) Create a Specialist with a Rack that manages the ZClass instances
that represent the objects from your database.
2a) In the Rack set the Storage tab so that it uses ClientObject
as the class of objects it manages, and choose "loaded by accessing attribute"
rather than "stored persistently". Set the attribute to 'client_name'.
2b) In the "Data PlugIns" tab clear out the persistent PlugIns and
replace them with a single SkinScript method with the following
lines:
------------------------------------------------------------
WHEN OBJECT ADDED CALL sqlInsertProduct(client_name=self.id,
email=self.email, rate=self.rate, last_payment=self.last_payment,
primary=self.primary, services=self.services)
WHEN OBJECT CHANGED STORE email, rate, last_payment, primary, services
USING sqlUpdateProduct(client_name=self.id, email=self.email, rate=self.rate,
last_payment=self.last_payment, primary=self.primary, services=self.services)
WHEN OBJECT DELETED CALL sqlDeleteProduct(client_name=self.id)
WITH QUERY lookup_product(client_name=self.id) COMPUTE
client_name, email,rate,last_payment,primary,services
------------------------------------------------------------
(The 'STORE ..' part on the WHEN OBJECT CHANGED line is
important to ensure that the Rack knows that these attributes
are being stored with this command.)
2c) Add ZSQL Methods, Python Methods/Scripts and DTML methods to the
Speciliast so that it can carry out it's program. Everything
*but* the SQL methods are covered in the previously mentioned
example. Here I'll only describe the ZSQL Methods used by the
SkinScript:
ZSQL Methods:
sqlInsertProduct, args:
client_name email rate last_payment primary services
code:
INSERT INTO clienttracker_table
(client_name, email, rate, last_payment, primary, services)
VALUES
(
<dtml-sqlvar client_name type=string>,
<dtml-sqlvar email type=string>,
<dtml-sqlvar rate type=string>,
<dtml-sqlvar last_payment type=string>,
<dtml-sqlvar primary type=string>,
<dtml-sqlvar services type=string>
)
sqlUpdateProduct, args:
client_name email rate last_payment primary services
code:
UPDATE clienttracker_table SET
email=<dtml-sqlvar email type=string>,
rate=<dtml-sqlvar rate type=string>,
last_payment=<dtml-sqlvar last_payment type=string>,
primary=<dtml-sqlvar primary type=string>,
services=<dtml-sqlvar services type=string>
where client_name=<dtml-sqlvar client_name type=string>
sqlDeleteProduct, args:
client_name
code:
DELETE FROM clienttracker_table WHERE
client_name = <dtml-sqlvar client_name type=string>
lookup_product, args:
client_name
code:
select * from clienttracker_table where
<dtml-sqltest client_name type=string>
3) Since the items are no longer stored persistently, you need
to change index_html to use a ZSQL Method to get the object
ids, rather than defaultRack.getPersistentItemIDs(). In a 'real'
situation this would probably be tied to some sort of search
interface.
Good Luck!
-steve
>>>>> "AP" == Aaron Payne <aaron@aaronpayne.com> writes:
AP> Hi all,
AP> I'm trying to use Gadfly as storage for a Zpatterns rack.
AP> With the following skinscript trigger I can view records in
AP> the database. But I can't insert a new one.
AP> WHEN OBJECT ADDED CALL sqlInsertProduct()
AP> WITH QUERY lookup_product(client_name=self.id) COMPUTE
AP> client_name,email,rate,last_payment,primary,services
AP> Where:
AP> sqlInsertProduct is a zsql method. args: client_name email
AP> rate last_payment primary services Query template: INSERT INTO
AP> clienttracker_table (client_name, email, rate, last_payment,
AP> primary, services) VALUES ( '<dtml-var client_name>',
AP> '<dtml-var email>', '<dtml-var rate>', '<dtml-var
AP> last_payment>', '<dtml-var primary>', '<dtml-var services>' )
AP> lookup_product is a zsql method. args: client_name Query
AP> template: select * from clienttracker_table where
AP> <dtml-sqltest client_name type=string>
AP> client_name,email,rate,last_payment,primary,services are
AP> fields of the table clienttracker_table and properties of the
AP> dataskin.
AP> If I remove "=self.id" from the trigger I am able to add a
AP> record to the db through the trigger. Without "=self.id" in
AP> the trigger I am unable to view the records in the db.
AP> I noticed in a post today that said
AP> ... you should probably choose some attribute other than 'id'
AP> as the attribute to check for your DataSkin. The 'id'
AP> attribute is always there...
AP> Objects are loaded by accessing attribute client_name and I
AP> still get the "object already exists" error.
AP> Questions: -Should I just create the record directly with the
AP> zsql method? That would defeat the purpose of using
AP> ZPatterns. -How do I eliminate the "already exists" error
AP> Zope version: Zope 2.2.1 Python version: 1.5.2 System
AP> Platform: freebsd4
AP> -Aaron
AP> _______________________________________________ Zope maillist
AP> - Zope@zope.org http://lists.zope.org/mailman/listinfo/zope **
AP> No cross posts or HTML encoding! ** (Related lists -
AP> http://lists.zope.org/mailman/listinfo/zope-announce
AP> http://lists.zope.org/mailman/listinfo/zope-dev )