History for SandBox
??changed:- Zope 2.2 Product Developer's Guide - Chapter III - Python Products Approaching the Zope Product API Extending Zope is quite simple compared to many other environments. Since Zope is based on the clear, elegant Python scripting language, Zope extensions are quick to develop and clear to maintain. However, since they can leverage the full power of the Zope framework, writing a Zope Product is more complicated than the extremely simple extensibility of External Methods. Fortunately the step up in complexity is much less than the dramatic increase in functionality. In this tutorial we are going to build a poll Product. The included Python and DTML files show some of the steps in the development of a sample poll Product. The 'Poll.tar.gz' file is the completed Product. To install the completed Product ungzip and untar it inside your Zope directory. Then shutdown and restart Zope to start using the sample poll Product. What you need to know before you begin Before you read this tutorial you should have a basic understanding of how Zope publishes Python objects. You should, of course, know Python reasonably well. If you've used object publishing before, perfect. If not, you might want to read an introduction to object publishing before you begin, because the Zope Product API is just a special case of object publishing programming. Finally you should have a reasonable familiarity with Zope itself. You should understand how to do things like create Folders and Documents, and use DTML to call methods, and set properties. The Zope Manager's Guide is a good place to learn how to use Zope. Defining and analyzing your task Writing a Zope Product, creating a website, building a database, all these activities are tasks which are done to solve specific problems. If you want to do a good job building a solution, you must understand your problem first. In the next section we'll talk about different approaches to solving problems in Zope. However, its a good idea to start with a description of the problem. Here's a short problem description and analysis for our poll project. Requirements Customers manage their areas of a Zope site and want to provide information services. In this case, a customer wants to collect feedback from users regarding a certain topic. That is, they want to conduct a poll. A poll contains ballot with question with one or more answers. The ballot is the HTML presentation of the question, answers, and control elements. Users can select only one answer for a poll. Users can either vote in the poll or view the current results or both. The results at any time are displayed by default as text using an attractive out-of-the-box format. The appearance of the ballot should be customizable, and the ballot should be able to be embedded in other documents. Finally, a poll should allow voting by only a select group of users that have the correct credentials. That is, should be able to be private. Analysis The Poll appears to have actors of Customer, User, Privileged User. The Customer actor is someone able to add and manage Zope content. The User actor is someone with the Anonymous role that interacts with Zope. A Privileged User appears to be a non-Anonymous Zope User. This means that the Poll should expose some permissions for operations such as voting and presenting results, allowing the permissions to include various roles. The Poll has a number of crisp abstractions. A Poll represents all the state and behavior needed to accomplish the task. A Ballot appears to be Document with some DTML scripting in it. A Question might not be a separate object. Answers might be separate objects that leverage the normal Zope Folder interface to manage them. Is the Product API right for the project? After you have described and thought about your pojects, the next step is to evaluate whether your idea would work well as a Product, or if it could be better implemented some other way. In our case we would like to build a poll product like you see on Slashdot and many other sites. We could probably build it with SQL Methods and DTML without too much difficulty. Though this would require mucking around with the RDBMS whenever you wanted to create a new poll or modify an existing poll. We could probably build a simple polling facility just using DTML, Documents and maybe properties. Again, this approach would probably involve more administration hassles than we would like. Using a Zope Product we could provide easy manageabiliy to Zope users who want to create their own polls. Using a Product also gives us fine control over access controls, and gives us room to refine and develop our poll over a period of time. So we have a marginal case for turning our idea into a Product. OK, good enough let's get going. Getting started in plain old Python Now that we have decided to harness the full power of the Zope Framework to create a reusable Zope Product, the first thing to do is to write a prototype in Python. This prototype will try to capture the essential algorithms of our product. It will also allow us to test the guts of the product and make sure they are sound before we start confusing ourselves with exotic Zopisms. Here's a first cut at what a poll class might look like:: class Poll: "A multiple choice poll." def __init__(self,question,choices): self.question=question self.choices=choices self.votes={} for choice in range(len(choices)): self.votes[choice]=0 def vote(self,choice): "vote for a choice" self.votes[choice]=self.votes[choice]+1 def total_votes(self): "total number of votes cast" total=0 for v in self.votes.values(): total=total+v return total def votes_for(self,choice): "number of votes cast for a given choice" return self.votes[choice] Basically our 'Poll' object keeps track of what is going on in a dictionary that maps choices to numbers of votes. The 'vote' method actually casts a vote. 'votes' is a dictionary keyed the the choice index which keeps track of the number of votes for each choice. The 'total_votes' and 'votes_for' methods just report statistics about the poll. Of note is the fact that we haven't made any effort to keep people from voting more than once. There are a number of ways we could handle this, for example we could somehow record the identity of everyone who voted. Then when someone tries to vote we could look them up in our list of people who have voted. This approach has some problems since it is often difficult to reasonably identify someone. Let's leave this problem unresolved for now. Testing our initial implementation in Python An original purpose of Zope was to hide the publishing details and allow Python developers to think in terms of Python. Thus, at this stage let's go into Python and test what we have. OK, so does our first attempt at a poll work? Let's exercise it a little:: def test(): p=Poll("What's for breakfast?",["spam","eggs","toast"]) p.vote(0) # vote for spam p.vote(2) # vote for toast p.vote(0) # vote for spam print p.total_votes() #returns 3 print p.votes_for(0) #returns 2 You can find this code in the included 'Poll1.py' example file. Run it and see for yourself that it works. At first glance it seems pretty reasonable. Though if you try to vote for a non-existent choice you get an 'KeyError'. Also there's nothing forcing you to initialize your poll class with reasonable arguments. Well that's OK for now. But we may want to add some error handling later. Zope provides a number of error handling features, like automated user notification of errors, and transaction handling to abort transactions when uncaught exceptions are raised. Adding a user interface OK, now we have a semi-functional poll, let's add a user interface so that people can actually use it through the web. The normal Zopish way to do this is to use DocumentTemplate. A product can [1131 more lines...]