ZSQL method attribute name question
I would like to be able to write generic handlers for data returned by ZSQL methods. To do this I need to know how to get access to the metadata for rows returned by ZSQL methods. If I define a class and associate it with a ZSQL method using the Advanced tab of that method's management page, what is the right way for that class to learn the names of the columns returned by the query? The following code works, but I was unable to find the __record_schema__ attribute in any Zope documentation and I am a little wary of using it unless I know it is legitimate, particularly since its name begins with two underscores. If there is a better way to do this I would really like to know. (Did I miss something obvious?) If I have a handler that contains: class handler: def munge(self): ret = "" for i in self.__record_schema__.keys(): ret = ret + "<br>" + str(i) + " = " + str(getattr(self, i)) return ret and the handler is associated with a ZSQL method named get_phonebook which simply runs "select * from phonebook" and I have a table in the database which looks like: create table phonebook ( first_name varchar, last_name varchar, address varchar, phonenumber varchar) then if I execute this page of DTML <!--#var standard_html_header--> <!--#in get_phonebook--> <!--#var munge--> <br> <!--#/in--> <!--#var standard_html_footer--> It shows me something like this: ADDRESS = London PHONENUMBER = 999-9999 LAST_NAME = Thomas FIRST_NAME = David ADDRESS = Berkeley PHONENUMBER = 888-8888 LAST_NAME = Herman FIRST_NAME = Tom which is what I want - the names of the columns and the values. One of the things that is not clear to me (and this may be a Pythonism, not a Zopism) is why I am able to retrieve the values for the columns by calling getattr(self, i) when, if I try to retrieve the object's attributes by calling dir(self) or just dir(), I don't see any of these attribute names. Obviously, this example is fairly contrived. I just wanted to show the mechanism I was after. What I really want to be able to do is call several ZSQL methods from an external method and play around with combinations of the results without having to know in advance exactly what to expect back from the ZSQL methods. Rob
Robert Carey wrote:
I would like to be able to write generic handlers for data returned by ZSQL methods. To do this I need to know how to get access to the metadata for rows returned by ZSQL methods.
If I define a class and associate it with a ZSQL method using the Advanced tab of that method's management page, what is the right way for that class to learn the names of the columns returned by the query?
ZSQL Methods return a sequence of record objects. These record objects are instanciated on the fly. You can even specify a class in the filesystem that defines your returned objects. These are called pluggable brains, and are probably what your looking for, because you can define the actualy object returned to you, and don't have to go sniffing on it to find out it's properties. -Michel
Michel Pelletier wrote:
Robert Carey wrote:
I would like to be able to write generic handlers for data returned by ZSQL methods. To do this I need to know how to get access to the metadata for rows returned by ZSQL methods.
If I define a class and associate it with a ZSQL method using the Advanced tab of that method's management page, what is the right way for that class to learn the names of the columns returned by the query?
ZSQL Methods return a sequence of record objects. These record objects are instanciated on the fly. You can even specify a class in the filesystem that defines your returned objects. These are called pluggable brains, and are probably what your looking for, because you can define the actualy object returned to you, and don't have to go sniffing on it to find out it's properties.
-Michel
I am somewhat confused. I thought that a pluggable brain was the same thing as a class associated with a ZSQL method. Is it something else? There are places where I would like to do some sniffing to determine properties, rather than hardcode them into a class definition. For example, what I wanted to do was write a generic method that could be used in more than one of those classes without the classes having to know anything about the details of the query they were written to support. Here is an artificial example. Suppose you wanted to construct a header out of the names of the columns in the relation returned by any query, and you wanted to be able to apply that header to a number of different queries. If this use of __record_schema__ is all right, you could do something like: # generic class - can be applied to any ZSQL method class handler: def title(self): ret = "" for i in self.__record_schema__.keys(): ret = ret + str(i) + " " ret = ret + "<br>" return ret # event-table specific class associated with ZSQL method getevent class event(handler): def get_event(self): return "<br>%10.10s:%10.10s..." % (self.name, self.description) # user-table specific class associated with ZSQL method getuser class user(handler): def get_user(self): return "<br>%s:%s" % (self.first_name, self.last_name) where "user" and "event" are classes designed to support the records returned by the specific ZSQL methods called "getuser" and "getevent." Then from DTML you could do something like: <!--#var standard_html_header--> <!--#in getuser--> <!--#if sequence-start--> <!--#var title--> <!--#/if--> <!--#var get_user--> <!--#/in--> <hr> <!--#in getevent--> <!--#if sequence-start--> <!--#var title--> <!--#/if--> <!--#var get_event--> <!--#/in--> <!--#var standard_html_footer--> This would display a result like: USER_ID USER_NAME LAST_NAME FIRST_NAME Marion:Sheckley Marcus:Booth Eva:Baumgarten Regina:Morse Vernon:Banks Byron:Keats ------------------------------------------------ ADDED_BY START_DATE RECURRING END_TIME SORT_ID LOCATION HAS_APPOINTMENT START_TIME CAPACITY EVENT_ID END_DATE DESCRIPTION NAME COST Early Bird:Come join ... Lazy Work :Rick is le... Current Ev:Come discu... Dahlia Dal:We are off... An Evening:We will di... Movie in t:Tonights m... Ignoring for the moment that in this context the generated page is not particularly meaningful, note that the header of each section was produced by the same piece of inherited code with no knowledge of the specific query. There are places where I would prefer to work in a way analagous to this rather than to have to code the header information specifically into individual classes such as "event" and "user." What I would like to know is if for i in self.__record_schema__.keys(): is a legitimate way to get at this information, and if it is not then is there another way that I can use? Or, for that matter, am I totally misusing the ZSQL class facility, and should I be doing something else? Is there a tutorial on ZSQL methods that goes into how to use pluggable brains? I love using Zope, but I sometimes have trouble knowing whether I am going with or against the grain of the system. Thanks, Rob
At 02:53 03/08/99 , Robert Carey wrote:
Michel Pelletier wrote:
Robert Carey wrote:
I would like to be able to write generic handlers for data returned by ZSQL methods. To do this I need to know how to get access to the metadata for rows returned by ZSQL methods.
If I define a class and associate it with a ZSQL method using the Advanced tab of that method's management page, what is the right way for that class to learn the names of the columns returned by the query?
ZSQL Methods return a sequence of record objects. These record objects are instanciated on the fly. You can even specify a class in the filesystem that defines your returned objects. These are called pluggable brains, and are probably what your looking for, because you can define the actualy object returned to you, and don't have to go sniffing on it to find out it's properties.
-Michel
I am somewhat confused. I thought that a pluggable brain was the same thing as a class associated with a ZSQL method. Is it something else?
No, Michel is not paying attention. You were using a pluggable brain, which is indeed a class associated with a ZSQL Method.
There are places where I would like to do some sniffing to determine properties, rather than hardcode them into a class definition.
For example, what I wanted to do was write a generic method that could be used in more than one of those classes without the classes having to know anything about the details of the query they were written to support.
Here is an artificial example. Suppose you wanted to construct a header out of the names of the columns in the relation returned by any query, and you wanted to be able to apply that header to a number of different queries. If this use of __record_schema__ is all right, you could do something like:
# generic class - can be applied to any ZSQL method class handler: def title(self): ret = "" for i in self.__record_schema__.keys(): ret = ret + str(i) + " " ret = ret + "<br>" return ret
# event-table specific class associated with ZSQL method getevent class event(handler): def get_event(self): return "<br>%10.10s:%10.10s..." % (self.name, self.description)
# user-table specific class associated with ZSQL method getuser class user(handler): def get_user(self): return "<br>%s:%s" % (self.first_name, self.last_name)
where "user" and "event" are classes designed to support the records returned by the specific ZSQL methods called "getuser" and "getevent."
Then from DTML you could do something like:
<!--#var standard_html_header-->
<!--#in getuser--> <!--#if sequence-start--> <!--#var title--> <!--#/if-->
<!--#var get_user--> <!--#/in-->
<hr>
<!--#in getevent--> <!--#if sequence-start--> <!--#var title--> <!--#/if-->
<!--#var get_event--> <!--#/in-->
<!--#var standard_html_footer-->
This would display a result like:
USER_ID USER_NAME LAST_NAME FIRST_NAME
Marion:Sheckley Marcus:Booth Eva:Baumgarten Regina:Morse Vernon:Banks Byron:Keats
------------------------------------------------
ADDED_BY START_DATE RECURRING END_TIME SORT_ID LOCATION HAS_APPOINTMENT START_TIME CAPACITY EVENT_ID END_DATE DESCRIPTION NAME COST
Early Bird:Come join ... Lazy Work :Rick is le... Current Ev:Come discu... Dahlia Dal:We are off... An Evening:We will di... Movie in t:Tonights m...
Ignoring for the moment that in this context the generated page is not particularly meaningful, note that the header of each section was produced by the same piece of inherited code with no knowledge of the specific query. There are places where I would prefer to work in a way analagous to this rather than to have to code the header information specifically into individual classes such as "event" and "user."
What I would like to know is if
for i in self.__record_schema__.keys():
is a legitimate way to get at this information, and if it is not then is there another way that I can use?
Or, for that matter, am I totally misusing the ZSQL class facility, and should I be doing something else? Is there a tutorial on ZSQL methods that goes into how to use pluggable brains? I love using Zope, but I sometimes have trouble knowing whether I am going with or against the grain of the system.
Thanks,
Rob
With Zope, the source is most often your documentation. And yes, what you are doing is legitimate and correct. I believe DC is in the process of officially documentating the source, therefore making it official. The fact you found __record_schema__, means you already know where to look. For those that don't, lib/python/Shared/DC/ZRDB/Results.py creates instances of the record object, which is based on a simple, empty class end an optional user specified filebased class, the pluggable brain. -- Martijn Pieters, Web Developer | Antraciet http://www.antraciet.nl | Tel: +31-35-7502100 Fax: +31-35-7502111 | mailto:mj@antraciet.nl http://www.antraciet.nl/~mj | PGP: http://wwwkeys.nl.pgp.net:11371/pks/lookup?op=get&search=0xA8A32149 ------------------------------------------
participants (3)
-
Martijn Pieters -
Michel Pelletier -
Robert Carey