[Zope-CVS] CVS: Packages/JobBoardEx - Tutorial.html:1.7

Guido van Rossum guido@python.org
Fri, 14 Jun 2002 10:41:13 -0400

Update of /cvs-repository/Packages/JobBoardEx
In directory cvs.zope.org:/tmp/cvs-serv18212

Added Files:
Log Message:
Re-adding this.

=== Packages/JobBoardEx/Tutorial.html 1.6 => 1.7 ===
+<title>The Job List Example in Zope3</title>
+<h1>The Job List Example in Zope3</h1>
+<p>This application will provide you with a simple but useful example
+in Zope3, which can be modified and adapted for your own purposes. It
+also demonstrates a pattern for you to follow when creating your own
+<p>The Job List allows users to post job information on a site, and to
+view a simple list of jobs. A particular job can be selected and
+viewed in detail. When a job is submitted for posting, the
+administrator of the job list can accept or reject the job. The
+administrator may also delete existing jobs from the list.
+<p>This example was created at the March 19-21, 2002 Sprint at the
+PythonLabs offices in Washington DC, lead by Jim Fulton and including
+Guido van Rossum, Jeremy Hylton, Tim Peters, Fred Drake, Barry Warsaw,
+Stephan Richter, and Bruce Eckel. The initial draft of this document
+was written by Bruce Eckel with help from Jim Fulton, on a train to
+New York City.  This document is placed in the public domain so that
+others may freely improve upon it, but if you do so please submit the
+result back to Zope Labs.
+<h2>Building applications with Zope3</h2>
+<p>One way to look at Zope in this case is as the controller of a
+state machine.  Your system will move through various states based on
+input (typically from the user through the web). In a particular
+state, the system will display a page and wait for the user to provide
+input and request a response. Based on the input and the request, the
+system will perform an operation and move to a new state.  So your
+primary job is to tell Zope what to do and what to display for each
+state, and how to move from state to state.
+<p>In addition, this application will make use of the fact that Zope
+is built on an object-oriented database. Anything that we want to be
+persistent in this application (for example, the jobs in the list)
+will be stored automatically in the Zope database. To do this, all we
+have to do is inherit a class from the <b>Persistent</b> base class,
+as you shall see.
+<h2>Entities/Business Objects</h2>
+<p>We'll start by defining what can be thought of as the "business
+objects," or simply the "entities": those classes that map directly
+from the conceptual model of the system. In this case, the model has a
+<b>Job</b> object which contains all the information about a single
+job, and a <b>JobList</b> object which holds the collection of
+<b>Job</b> objects, and also controls the addition and removal of
+<b>Job</b> objects to itself.
+<p>We want to tell Zope how the Job and JobList should be created,
+edited, viewed, etc. so that Zope can perform these operations on its
+own. We do this by:
+<li>Creating an interface for each entity. The interface is used by
+Zope to hook the various views to the entity.</li>
+<p><li>Creating one or more classes that implement that
+interface. These classes perform the actual "business logic" for your
+application, but they don't control the views (they don't have
+anything to do with views -- if you asked them about thier views, they
+wouldn't know what you're talking about).</li>
+<p><li>Creating one or more Zope Page Template files (.pt files), used
+to create the views on an interface.</li>
+<p><li>Creating a view class that contains both the logic for the
+presentation layer and the presentation itself. The presentation is
+described in the separate ZPT files mentioned above. The logic for the
+presentation layer consists primarily of the actions that occur when
+the buttons on your web forms are pressed. In more sophisticated
+examples than this one, the view class might also do things like
+convert data into an appropriate format for display.</li>
+<p><li>Modifying the configuration (.zcml) file to give Zope the
+recipe of how all these things fit together.</li>
+<h2>Job Objects</h2>
+<p>We'll start by creating the Job Object and its views.
+<h3>The IJob Interface</h3>
+<p>The primary task of the Job object is to hold information about a
+job. In IJob.py, you can see that most of the elements in the
+interface are Zope attributes, defined by the Attribute() function in
+Zope's Interface module.  Attribute() is a way to define attributes in
+an interface. After all the attributes, there is a method, approve(),
+which is used to take the job from the PendingApproval to the Approved
+state. These states are defined in the class JobState.
+<p>Note that there is no awareness of display in either the IJob
+interface or the Job class.
+<h3>The Job class</h3>
+<p>Because we want it to be automatically stored in the Zope database,
+the Job class is inherited from Persistent. In addition, it is marked
+as implementing the IJob interface with the __implements__
+assignment. The initialization code simply creates and initializes the
+fields from the arguments, and puts the object in the PendingApproval
+state. The approve() method changes the state to Approved.
+<h3>The JobView class</h3>
+<p>JobView tells Zope how to display a Job. JobView inherits
+AttributePublisher, which is the big clue that this is a view class,
+since that base class is only associated with view classes. The
+AttributePublisher class includes an
+<pre> __implements__ = IBrowserPublisher </pre>
+<pre> __used_for__ = IJob </pre>
+statement allows Zope to check to make sure that the JobView class is
+only used for IJob objects during the configuration of the system, and
+to report an error if it is used incorrectly.
+<p>An instance of a view class is only ever associated with a single
+object to be viewed. In this case, it's a Job object so the __init__()
+stores the associated Job object and getContext() produces
+it. (getContext() is called when ...).
+<p>Although the <b>index</b> assignment initially appears to be
+creating a simple attribute to the JobView class, it's actually
+creating a method. The PageTemplateFile() function takes a Zope Page
+Template description and compiles it to produce a callable (in this
+situation) object which thus behaves as a method. So you can treat
+that expression as creating a method for the class, just like
+<b>def</b> creates a method.
+<p>The <b>index</b> method is treated specially by Zope. When you ask
+for a view (typically through a URL, by specifying the object and then
+the view you want on that object), if you don't otherwise say the
+particular view you are looking for then Zope will look for a method
+named <b>index</b> and use that. So in JobView we're saying that
+PageTemplateFile('JobView.pt') is the default view for that object.
+<p><i>Note: the methods that wrap the attributes are necessary to
+allow access control for those attributes, until this issue is fixed
+in Zope3.</i>
+<h3>Editing a Job with JobEditView</h3>
+<p>The JobEditView class in association with the JobEditView.pt and
+JobPreviewView.pt page templates define the process of editing a
+Job. This starts on the page produced by JobEditView.pt. If you look
+at this code, you'll see relatively normal HTML with some extra "tal"
+information buried in the tag fields. Leaving that aside for the time
+being, we're primarily interested in the form's "action" and the
+"submit" inputs (the buttons). The "action" is set to "", which means
+(to the browser) "back to the object that created the page." In this case,
+that means the JobEditView object. When you combine this fact with the
+"submit" inputs, for "Preview" and "Cancel," we produce the desired
+results. The name for the preview button is "preview:method". This
+tells Zope that when that button is pressed it should call a method
+named "preview," and since "action" is "", that indicates that Zope
+should call the preview method on the page's current object, a
+JobEditView. So it calls JobEditView's preview() method, which you can
+see will produce another page, created with the expression
+PageTemplateFile('JobPreviewView.pt'). If instead you press the
+"cancel" button, the name associated with that button is
+"cancel:method" so the JobEditView cancel() method will be
+called. Note that this is a regular def method.
+<p>The submit() method is called from the JobPreviewView.pt in the
+same way. The same edit() and cancel() methods are also called from
+<p>You can see that the view classes don't just display pages, but
+they also contain control logic that will respond to actions on those
+views. If you are thinking in terms of model-view-controller, what you
+see here is only a partial fullfillment of that idea. True, as much of
+the "controller" aspect as possible is built into the standard Zope
+code (and is thus "under the covers" from the perspective of our
+application), and the goal is to just tell Zope how to do the
+controlling for you. But it's inevitable that you must put <i>some</i>
+control code in your system, and it turns out that control code is
+typically highly coupled with view code, and so it's cleaner to
+include the control code, such as the cancel() and submit() methods,
+in the view class. Thus we end up with more of a view/controller. The
+trick is not to give into the temptation to put all your logic in the
+view class, because doing so leads you down the Visual Basic path,
+which inevitably produces applications that are problematic to
+maintain and that don't scale well.
+<h2>IJobList and Joblist</h2>
+<h2>Viewing a Joblist</h2>
+<h2>Page Templates</h2>
+<p>In the previous section there was a bit of introduction to page
+templates.  Here we'll go into detail and explain how page templates
+are associated with objects, and how they extract information from
+their objects.
+<h2>Tying it all together with the configuration file</h2>
+<p>Finally, we need to tell Zope what's what with all these classes --
+how they are supposed to interact with each other and what permissions
+to allow.