How To: Build a searchable Job Board
0.0 Introduction
This short howto is a simple walk-through or tutorial to demonstrate how
Zope can be used to build interesting "web-apps". It was
inspired by the Job Board example from the doc:
A Technical Introduction to Object Publishing with Zope by
Brian Lloyd and Amos Latteier from digicool.com. It does not
however, use the same methods. It's an alternative Job Board.
To view a working example of it, see
here.
This Howto is dedicated to all struggling Zope newbies.
We were all newbies, once. :-)
|
Note:
If you're using Zope-2.1.0 and above, you'll need to disable SubTransactions for the
job board entries' Catalog. Or the searching won't work as expected immediately after
you add new entry objects.
|
|
Update:
If you're using Zope-2.2.0 and above, you'll need an
extra step to enable "Anonymous" entry additions.
Go to the folder where the entry_addForm is stored,
click on the "Security" tab at the top. Check the box
for "Add Job Board Entry" on the Anonymous column.
This should avoid the authorization failures.
|
So, who is the intended reader?
- You are relatively new to zope.
- You have zope set up and running - you get the "Welcome to Zope" page when you access your zope site.
- You know some dtml (but you're not a jedi yet :))
- You know how to add, delete etc. objects from the zope odb.
- You are new to Z Classes and want to know how to build one.
- You are new to Z Catalogs and want to see a practical example of searching Z Catalogs.
Obviously, this is not intended for Zope gurus. Some things will be
rather simplified and not as 'tidy' as one would like. Also, I will explain a lot of things
which would be obvious to the average web guru. I've tried to make this howto
accessible to not only Zope newbies but also to those new to programming in general.
So, what are we going to do?
Here's the Scope of this howto:
| Scope |
The Job Board is a board where anyone can post job offers (like you find in newspaper
classifieds and job "notice boards"). That is, it is publicly postable and readable.
Like a 'real' job board. However, unlike a physical one, you'll also be able to search
the board for jobs based on your own search criteria. (say, company or job name)
In summary, a user will be able to:
- Add a new entry onto the Job Board
- View all the entries on the Job Board
- Search the Job Board for jobs
|
Okay, let's begin. Point your browser to your Zope site and log in to the management interface.
1.0 Create the Job Board Folder
The first thing to do is to create the folder where this little app will live.
Add a folder with Id "Job_Board". Leave the default check-boxes on. You'll want an
"index_html". Then, add another folder within the Job_Board folder -
give it the Id "entries". This folder will store our job board entries.
Next add a ZCatalog object. Give it the Id "Catalog" - the
name of this catalog is important. The 'C' is capital.
2.0 Create the Job Board Entry ZClass
We want to make a template for adding job offers. For this, we'll create
a ZClass. The instances are later created by the users themselves as and when they
have new jobs to offer without entering the management interface.
Go to the "Products" folder in the "Control_Panel" at the top. Add a new product with
Id "JobBoard". Click on it.
Now add a new Z Class. Give it an Id "job_board_entry", Meta Type "Job Board Entry".
Make sure "Create constructor objects" is checked. In the Base Classes section,
add CatalogAware as a base class. Then click "Add".
3.0 Customize the job_board_entry Z Class
Now that we've created the Z Class, it's time to customize it. Click on the job_board_entry class
(it's got that "tin can" icon). Let's create some properties to be the job_board_entry class'
attributes. Click on the Property Sheets tab (at the top). Add a new property sheet by
clicking Add. Give the property sheet the Id "entry_info". Click on it.
Let's add some properties. Add these:
| Id | Type | Value |
| position_name | string | [string] |
| position_about | lines | [lines] |
| position_pay | float | 0.0 |
| org_name | string | [string] |
| org_homepage | string | [string] |
| org_about | text | [text] |
| contact_name | string | [string] |
| contact_email | string | [string] |
| contact_phone | string | [string] |
| offer_expires | string | [string] |
| title | string | [string] |
Apart from the required "0.0" for float type, why did we put values "[string]" etc
in the other properties? It's not required but I find that it's easier to
see what types those properties are later. Also, why didn't we use type "date" for the
offer_expires property? Well, we could but then you would not be able to put values like
"Never" or "Real Soon" in it. The type "date" is an object with methods. Not a simple type.
3.1 Customize job_board_entry_add method
When an entry is created, each entry object needs an "id". A unique identifier. Normally,
when you create an object using the management interface, Zope will as you to specify the
object's "id". We could do that for our entry object as well, but you'd have to make the user
or zope check for conflicting ids at creation time - this is sub-optimal to say the least.
The solution to this is to get Zope to generate ids automatically. For this, we'll
use the trick suggested in "HowTo: AutoGenerate Random ID for Objects" by Bill (check the "howto" pages
on the zope.org website for more tricks and tips!).
Basically, you use a time-stamp generated from the machine's rtc. So, each job_board_entry
object will have a string of numbers for their ids. Something of the form: 940962299.
To do that, you need to customize the job_board_entry_add method:
Get to the JobBoardProduct folder. Below the job_board_entry class, you'll see
a method labeled "job_board_entry_add". Click on it.
Add the lines in bold to the method:
| job_board_entry_add |
<HTML>
<HEAD><TITLE>Add job_board_entry</TITLE></HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<dtml-comment> We add the new object by calling the class in
a with tag. Not only does this get the thing
added, it adds the new thing's attributes to
the DTML name space, so we can call methods
to initialize the object.
</dtml-comment>
<dtml-comment>
The dtml-calls below are for auto-id during object
initialization.
</dtml-comment>
<dtml-call "REQUEST.set('ts', ZopeTime())">
<dtml-call "REQUEST.set('id',_.str(_.int(ts)))">
<dtml-with "job_board_entry.createInObjectManager(REQUEST['id'], REQUEST)">
<dtml-comment>
You can ad code that modifies the new instance here.
For example, if you have a property sheet that you want to update
from form values, you can call it here:
<dtml-call "propertysheets.Basic.manage_editProperties(REQUEST)">
</dtml-comment>
<dtml-call "propertysheets.entry_info.manage_editProperties(REQUEST)">
<dtml-call reindex_object>
</dtml-with>
<dtml-comment> Now we need to return something. We do this via
a redirect so that the URL is correct.
Unfortunately, the way we do this depends on
whether we live in a product or in a class.
If we live in a product, we need to use DestinationURL
to decide where to go. If we live in a class,
DestinationURL won't be available, so we use URL2.
</dtml-comment>
<dtml-if NoRedir>
<dtml-else>
<dtml-if DestinationURL>
<dtml-call "RESPONSE.redirect(DestinationURL+'/manage_workspace')">
<dtml-else>
<dtml-call "RESPONSE.redirect(URL2+'/manage_workspace')">
</dtml-if>
</dtml-if>
</BODY>
</HTML>
|
Note: The 2 lines (dtml-call) in bold above tells Zope to update the properties of the newly created
objects and the then re-index the ZCatalog, respectively.
If you've got some experience with Zope you quickly realize that if you used the
management interface to browse through your entries that it is difficult to determine
the objects just from a number. Not to worry, Zope objects have the attribute "Title"
which we will use to allow humans to tell at a glance what the objects are. Yes, they
are the titles in parentheses, next to the object ids.
The nice thing about this is that you can have the same titles for two objects with
different Ids. This is analogous to two people with the exact same name - but having
different identities. We will also create the titles automatically as we'll see later.
3.2 Create job_board_entry Z Class view methods
Now then, wouldn't it be great if our job_board_entry class instances could display
themselves? Well, they can! Click on the "Methods" tab.
Add these two methods: "index_html" and "content_html".
Here's what they look like: (The dtml tags are in bold to highlight them)
| content_html |
<TABLE border="1" bgcolor="aliceblue">
<TR><TH colspan="2" bgcolor="lightblue">Job Offer Entry Object: <dtml-var id></TH><TR>
<TR><TD bgcolor="lightblue"><B>Organization:</B></TD><TD><dtml-var org_name></TD></TR>
<TR><TD bgcolor="lightblue"><B>Homepage:</B></TD><TD><dtml-var org_homepage></TD></TR>
<TR><TD bgcolor="lightblue"><B>About:</B></TD><TD><dtml-var org_about newline_to_br></TD></TR>
<TR><TD bgcolor="lightblue"><B>Position:</B></TD><TD><dtml-var position_name></TD></TR>
<TR>
<TD bgcolor="lightblue"><B>Description:</B></TD>
<TD>
<UL>
<dtml-in position_about>
<dtml-let item=sequence-item>
<dtml-if item>
<LI><dtml-var item></LI>
</dtml-if>
</dtml-let>
</dtml-in>
</UL>
</TD>
</TR>
<TR><TD bgcolor="lightblue"><B>Pay Offered:</B></TD>
<TD>
<dtml-if "position_pay==0.0">
Contact Us
<dtml-else>
<dtml-var position_pay>
</dtml-if>
</TD></TR>
<TR><TD bgcolor="lightblue"><B>Offer Expires:</B></TD><TD><dtml-var offer_expires></TD></TR>
<TR><TD bgcolor="lightblue"><B>Contact:</B></TD><TD><dtml-var contact_name></TD></TR>
<TR><TD bgcolor="lightblue"><B>Email:</B></TD><TD><dtml-var contact_email></TD></TR>
<TR><TD bgcolor="lightblue"><B>Phone:</B></TD><TD><dtml-var contact_phone></TD></TR>
</TABLE>
|
| index_html |
<dtml-var standard_html_header>
<dtml-var content_html>
<dtml-var standard_html_footer>
|
You might be wondering, with the index_html being only 3 lines, why not combine the two
dtml methods into one? The reason is this: "index_html" is always the default dtml method
called when you view an object in zope (this applies to folders as well).
What this means is that when you view the object on its own, you'll get the content
plus the standard html headers and footers. However, if you're viewing a list of these
objects on a page (ie. another dtml method or document), then that page would
already have the standard footers and headers. On that page, you only call the objects'
"content_html" methods and not the "index_html" one.
If you're confused, don't worry, this concept will be clearer as we go along.
4.0 Create methods for public object creation
Normally, you can only add new objects through the Zope management interface with the
by-now-familiar "Add" button. This is because you want only users with the right access
rights to add objects into you Zope site. (As specified in the various acls in the Zope
folders.) Normally, the "job_board_entry_addForm" would be used to fill in the details (attributes)
for an entry - if you're going to add entry objects through the management interface,
you'll need to check that this method is correct.
However, since this is going to be a public posting board, you'll want to allow anyone
to add job offers / notices to the job board. After all, that's what it's for. To do
that, we'll add 2 methods in the "entries" folder. (ie. ~/Job_Board/entries/) Go to that
folder and "Add" 2 dtml methods, name them as below.
We will need to create two methods. One is the "job_board_entry_addform" equivalent and the other is the
addform processor method which will process the data from the webform. (dtml tags are in bold)
| entry_addForm |
<dtml-var standard_html_header>
<H2>Add Job Board Entry</H2>
<FORM action="entry_addProcessor">
<TABLE border="0">
<TR><TH>Organization</TH>
<TD><input type=text name=organization size="35"></TD>
</TR>
<TR><TH>Homepage</TH>
<TD><input type=text name=homepage size="35"></TD>
</TR>
<TR><TH>About</TH>
<td><textarea name="about:text" rows="8" cols="35"></textarea></TD>
</TR>
<TR><TH>Position</TH>
<TD><input type=text name=position size="35"></TD>
</TR>
<TR><TH>Description</TH>
<TD><textarea name="description:text" rows="8" cols="35"></textarea></TD>
</TR>
<TR><TH>Pay Offered</TH>
<TD><input type=text name=pay value="0.0"></TD>
</TR>
<TR><TH>Offer Expires</TH>
<TD><input type=text name=expires></TD>
</TR>
<TR><TH>Contact</TH>
<TD><input type=text name=name size="35"></TD>
</TR>
<TR><TH>Email</TH>
<TD><input type=text name=email size="35"></TD>
</TR>
<TR><TH>Phone</TH>
<TD><input type=text name=phone size="35"></TD>
</TR>
<TR>
<TD></TD>
<TD><input type=submit value=" Add Entry "><input type=reset value=" Clear Form "></TD>
</TR>
</TABLE>
</FORM>
<P>
<TABLE border="1">
<TR><TH colspan="2" bgcolor="lightblue">Usage</TH></TR>
<TR><TH>Organization</TH>
<TD>Name of organization eg. <I>Malaysian Open Source Group</I></TD></TR>
<TR><TH>Homepage</TH>
<TD>Website address without "http://" eg. <I>www.my-opensource.org/oss/</I></TD></TR>
<TR><TH>About</TH>
<TD>Short intro to your organization's activities</TD></TR>
<TR><TH>Position</TH>
<TD>Position offered eg. <I>System Administrator</I></TD></TR>
<TR><TH>Description</TH>
<TD>Short Job description - each line becomes a bullet list item.</TD></TR>
<TR><TH>Pay Offered</TH>
<TD>In RM eg. <I>2000.0</I> - entering 0.0 will display "Contact Us" when viewed</TD></TR>
<TR><TH>Offer Expires</TH>
<TD>When this offer expires eg. <I>dd/mm/yyyy</I> or <I>Never</I></TD></TR>
<TR><TH>Contact</TH>
<TD>The contact person eg. <I>The Manager</I> or <I>Dr. Nah</I></TD></TR>
<TR><TH>Email</TH>
<TD>Contact person's email eg. <I>docn@my-opensource.org</I></TD></TR>
<TR><TH>Phone</TH>
<TD>Contact person's phone number</TD></TR>
</TABLE>
</P>
<dtml-var standard_html_footer>
|
| entry_addProcessor |
<dtml-var standard_html_header>
<dtml-call "REQUEST.set('org_name', organization)">
<dtml-call "REQUEST.set('org_homepage', homepage)">
<dtml-call "REQUEST.set('org_about', about)">
<dtml-call "REQUEST.set('position_name', position)">
<dtml-call "REQUEST.set('position_about', description)">
<dtml-call "REQUEST.set('position_pay', pay)">
<dtml-call "REQUEST.set('offer_expires', expires)">
<dtml-call "REQUEST.set('contact_name', name)">
<dtml-call "REQUEST.set('contact_email', email)">
<dtml-call "REQUEST.set('contact_phone', phone)">
<dtml-call "REQUEST.set('title', organization+' - '+position)">
<dtml-with "manage_addProduct['JobBoard']">
<dtml-call "job_board_entry_add(_.None, _, NoRedir=1)">
</dtml-with>
<CENTER>
<H2>Thank you for your entry</H2>
<dtml-var linkto_frontpage>
</CENTER>
<dtml-var standard_html_footer>
|
The first method is pretty much standard for a webform. Those of you familiar with such
things will not find anything out of the ordinary. However, note the line:
<FORM action="entry_addProcessor">
That's right. Normally, you would put here the url of a cgi script. But in Zope, you
just call another method. Cool. The interesting stuff is in the entry_addProcessor method.
This is where we assign the data from the form's fields to the actual object's attributes.
This is done by the many <dtml-call...>.
Look at the dtml-calls. You'll notice that the var-names from the html form are
mapped to the objects attributes. Actually, there's no reason why the attribute names
and the webform field names cannot be exactly the same. I made them this way so that
you can see which part is which in the code.
Look at this line:
<dtml-call "REQUEST.set('title', organization+' - '+position)">
This is where we assign the "title" of the object. (remember when we coded the autogenerate
IDs?). Here, we set the title so that is a combination of the organization and the position
offered. This makes it easy to spot, at a glance, what those objects are when you're browsing
the list of items in the "entries" folder using the management interface. Note that its
possible for two different objects to have the same title. This is okay, since they would
have different object IDs. (ie. those numbers)
Lastly, look at the code snippet below:
<dtml-with "manage_addProduct['JobBoard']">
<dtml-call "job_board_entry_add(_.None, _, NoRedir=1)">
</dtml-with>
The "entry_addProcessor" actually does call the real method to create an "entry"
object. But "NoRedir" is set to "1" so that the browser is not redirected as is the normal
case when using the management interface. (Try adding an object normally). So, the
user will see the next lines of HTML acknowledging the addition / creation of the new "entry"
object. If an error were to occur while processing, you won't get to see the "Thank you"
message. (Which is good, btw. We don't want to give a false impression, do we?)
Important:The "entry_addProcessor" must be set to "Manager" proxy for it to work.
Click on the "entry_addProcessor" dtml method and click on the "Proxy" tab at the top.
Make sure that Proxy Role "Manager" is highlighted and click the "Change" button. This
'proxying' is what enables an anonymous user to add new entry objects.
The "entry_addProcessor" method acts with the manager's role. This is a very powerful
thing so be sure you know what you're doing when you assign public methods the manager's
role. In this Job Board case, we want this ability.
5.0 Viewing the Job Board
Okay, so now we have our class done, we can add new job board entries. First, let's
build the actual web page where the job board will be viewed.
The "welcome" page you will see on the demo site is the one below. Customize to your
own needs.
| index_html |
<dtml-var standard_html_header>
<TABLE border="0">
<TR>
<TH bgcolor="lightblue">
<H2>Welcome to the my-oss IT Job Board!</H2>
</TH>
</TR>
<TR>
<TD>
<P>
<B>T</B>his is a simple web application using zope. The purpose of this
website is for people to post job offers and for people to look for interesting
jobs in the local IT industry (preferably using or building open source projects).
</P>
<P>
<B>T</B>his site was made primarily to demonstrate the use of <A href="http://www.zope.org">Zope</A>
as a web application tool to the <A href="http://www.my-opensource.org">Malaysian Open Source Group</A> members.
</P>
<P>
<B>H</B>opefully, members of the local open source community will also find paying jobs
to sustain themselves while they hack open source code. It's also for companies that are
looking for knowledgeable IT personnel whose job will entail common
open source systems like Apache site admin or programming with egcs and python.
</P>
<P>
<B>B</B>etter yet, if you happen to be looking for open source developers for
an open source project, you can post an offer here. (maybe contract work?)
</P>
<P>
<B>I</B>t is my hope that this site becomes more than a toy and that both
prospective employers and employees will find it useful.
</P>
</TD>
</TR>
<TR>
<TD>
To see how it works, you can:
<OL>
<LI><A href="viewJobBoard">View the Job Board</A></LI>
<LI><A href="entries/entry_addForm">Add an entry to the Job Board</A></LI>
<LI><A href="entry_search">Search the Job Board</A></LI>
</OL>
</TD>
</TR>
</TABLE>
<dtml-var ZopeAttributionButton>
<dtml-var standard_html_footer>
|
Notice this line:
<LI><A href="viewJobBoard">View the Job Board</A></LI>
The "href" is actually referencing a dtml method - in this case "viewJobBoard". Let
me explain a bit here. The reason why dtml methods are called methods is because
they are methods of the object in which they live or which they are a part of. In this case,
it is a method of the job board object (which is really just a folder object) that implements
a view. Object oriented programmers will now understand this method concept in Zope.
(and in the process, acquire some Zope Zen :-))
So what does the dtml method "viewJobBoard" look like? See below. As usual, dtml is
in bold. Note that the method resides within the "Job Board" folder.
(It is a method of that folder object).
| viewJobBoard |
<dtml-var standard_html_header>
<H2>The Job Board</H2>
<dtml-with entries>
<TABLE border="0">
<dtml-in "objectValues(['Job Board Entry'])">
<TR><TD><dtml-var content_html></TD></TR>
</dtml-in>
</TABLE>
</dtml-with>
<dtml-var linkto_frontpage>
<dtml-var standard_html_footer>
|
The dtml:
<dtml-in "objectValues(['Job Board Entry'])">
<TR><TD><dtml-var content_html></TD></TR>
</dtml-in>
Instructs Zope to look for objects with that Value attached to them. In this case, all
objects that have the "meta-type" of "Job Board Entry". What this dtml-in does is loop
through all the objects within that folder and if the object is that meta-type,
its content_html method is called.
The "linkto_frontpage" line there is just another dtml method (living in the same
folder) as a convenient way to make links to the front page. It is a one liner:
| linkto_frontpage |
<P><A HREF="Job_Board"><H4>Back to front page.</H4></A></P>
|
Some of you might be wondering: "Why are we even bothering to create such a simple
one liner dtml method?" Well, the reason is that, now we can use a short single line
within any other dtml methods or dtml documents as shown in "viewJobBoard" above. This
same line can be used anywhere dtml is used and any number of times. The benefit? Should
we need to change that link, we only need to do it once (in the actual "linkto_frontpage"
dtml method) and it will immediately work throughout the site.
For those who are wondering, yes, that's exactly the reason the dtml methods
"standard_html_header" and "standard_html_footer" exist (and work the way they do).
But there's more! What if, for the whole site, you want a certain "standard_html_header"
except for a few folders you want different "standard_html_header" dtml methods?
No problem, just make new ones in those folders. They will override the one
in the top level folder. This phenomenon is called "acquisition" in Zope-speak
and after you've played around with Zope, you'll agree it's pretty simple but
very powerful.
6.0 Searching for Job Board Entries
Our little job board is now pretty functional as it is and you can already put it to
good use. However, like I promised earlier, we want to go one-up on the real
"paper and pins" job boards. You can scan the board for interesting entries
but what if the board became super successful and there are hundreds of entries?
This is where automated searching can give our Zope job board the edge over
conventional ones.
Searching (for objects) in Zope is done using the ZCatalog. As you'll see,
ZCatalog is pretty nifty, to say the least. You can use it to catalog and later
search for any object or attribute of objects within the context of the Catalog.
ZCatalogs are special objects but still objects nonetheless with their own attributes and
methods. We've already created one at the start of this tutorial so all we need to
do is customize it!
6.1 Customizing the ZCatalog
The ZCatalog catalogs objects for quick searching. The first thing we need to do is
to customize the MetaData Table. Go to the Job Board folder object and click on the
Catalog object. At the top of the page, click on the MetaData Table tab.
The MetaData Table stores bits of information you want to have ready to display
in the results page. They are taken from the objects themselves and stored in the table.
So, each object will have it's own row. You'll want to have a minimum of items
stored here since it's only needed to give a quick look at the objects. For the real
details, we will call the objects themselves (via their content_html method).
Data stored in this table will be used to populate the results table generated from the search.
Make sure these items are in the list:
(Some are already listed)
- id
- contact_phone
- offer_expires
- position_name
- org_homepage
- contact_email
- meta_type
- contact_name
- org_name
The next thing to do is to index the catalog with items that will be used to search it. That sounds
complicated than it really is. Basically, the items you specify to be indexed will be used in the
search. Click on the Indexes tab at the top.
Add these items to the index list:
(They are all text-indexes)
- position_name
- position_about
- org_name
- org_about
- org_homepage
These will also be the fields for the search form as we shall see later.
Next click on the Status tab. Make sure that Substransactions is Disabled. Disable it
if it isn't.
6.2 Creating the ZCatalog Search Interfaces
Now that we have a catalog, we'll want to make interfaces for it so we can use it. Go back 'out' of the
Catalog. Make sure you can see the "Catalog" and "Entries" folders on this level. (this is the Job Board
folder). Select Z Search Interface and click Add to add the Z Search Interface.
In the Add form, Click on "Catalog" (ie. make sure it is highlighted), report style set to "Tabular".
For the text fields:
| Field | Value |
| Report Id | entry_report |
| Report Title | Entry Search Result |
| Search Input Id | entry_search |
| Search Input Title | Search for Entries |
The two dtml methods will be created. We will need to customize the two methods. So, click on them and
edit both methods so they look similar to the examples below.
| entry_search |
<dtml-var standard_html_header>
<FORM action="entry_report" method="get">
<H2><dtml-var document_title></H2>
Enter query parameters:<BR>
<TABLE>
<TR><TH>Organization</TH>
<TD><INPUT name="org_name"
width=30 value=""></TD></TR>
<TR><TH>Homepage</TH>
<TD><INPUT name="org_homepage"
width=30 value=""></TD></TR>
<TR><TH>About</TH>
<TD><INPUT name="org_about"
width=30 value=""></TD></TR>
<TR><TH>Position</TH>
<TD><INPUT name="position_name"
width=30 value=""></TD></TR>
<TR><TH>Description</TH>
<TD><INPUT name="position_about"
width=30 value=""></TD></TR>
<TR><TD colspan="2" align="center">
<INPUT type="SUBMIT" name="SUBMIT" value="Submit Query">
</TD></TR>
</TABLE>
</FORM>
<P>
<TABLE border="1">
<TR><TH colspan="2" bgcolor="lightblue">Usage</TH></TR>
<TR><TH>Organization</TH><TD>Name of organization eg. <I>Malaysian Open Source Group</I></TD></TR>
<TR><TH>Homepage</TH><TD>Website address without "http://" eg. <I>www.my-opensource.org/oss/</I></TD></TR>
<TR><TH>About</TD><TD>Keywords regarding organization's activities eg. <I>computers</I></TD></TR>
<TR><TH>Position</TD><TD>Position you're interested in eg. <I>System Administrator</I></TD></TR>
<TR><TH>Description</TH><TD>Keyword from job description eg. <I>flexible hours</I></TD></TR>
</TABLE>
</P>
<dtml-var standard_html_footer>
|
| entry_report |
<dtml-var standard_html_header>
<dtml-in Catalog size=50 start=query_start>
<dtml-if sequence-start>
<dtml-if previous-sequence>
<A href="<dtml-var URL><dtml-var sequence-query
>query_start=<dtml-var previous-sequence-start-number>">
(Previous <dtml-var previous-sequence-size> results)
</A>
</dtml-if previous-sequence>
<TABLE border>
<TR>
<TH>Organization</TH>
<TH>Homepage</TH>
<TH>Position</TH>
<TH>Offer Expires</TH>
<TH>Contact</TH>
<TH>Email</TH>
<TH>Phone</TH>
</TR>
</dtml-if sequence-start>
<TR>
<TD><dtml-var org_name></TD>
<TD>
<A href="http://<dtml-var org_homepage>">
<dtml-var org_homepage></A>
</TD>
<TD>
<A href="<dtml-var "Catalog.getpath(data_record_id_)">">
<dtml-var position_name></A>
</TD>
<TD><dtml-var offer_expires></TD>
<TD><dtml-var contact_name></TD>
<TD><dtml-var contact_email></TD>
<TD><dtml-var contact_phone></TD>
</TR>
<dtml-if sequence-end>
</TABLE>
<dtml-if next-sequence>
<A href="<dtml-var URL><dtml-var sequence-query
>query_start=<dtml-var next-sequence-start-number>">
(Next <dtml-var next-sequence-size> results)
</A>
</dtml-if next-sequence>
</dtml-if sequence-end>
<dtml-else>
There was no data matching this <dtml-var title_or_id> query.
</dtml-in>
<dtml-var linkto_frontpage>
<dtml-var standard_html_footer>
|
I have not marked any bold items this time since there are many instances where
the generated dtml methods differ from the ones above. Either customize it to your
needs or simply copy and paste.
Now that we've got all the pieces done, all we need to do now is create some
Job Board Entry objects. (ie. instances of the class) Go to the Job Board folder and
click on the View tab. This will call that folder's index_html method. Select
the add new entry and add one. (You can also call the "enter_addForm" dtml method from
within the "Entries" folder directly.) Add another entry. Make it 3 or 4.
Check that the objects are actually generated in the "Entries" folder.
View the created objects and make some searches. This is where you might need to
fix some bugs. It happens. I know this is obvious to many of you but please do
check and test your web apps before you make it "live" on the internet or intranet.
That's about it, really. Congratulations for staying with it!
7.0 Conclusion
We have actually covered quite a lot of ground. Specifically:
- Defining new ZClasses
- Creating object "publishing" methods (content_html)
- "Public access" object creation (or class instantiation)
- Cataloging objects
- Creating search interface
Which pretty much covers the basics of using Zope and its features. Of course,
this tutorial only scratches the surface of what Zope can do but it is my hope that
you, the reader, at least come to appreciate the power and simplicity of the Zope web
application environment.
Where to from here? Well, there are a few things you can try like tweaking the methods
or maybe add a hyperlink to the email address to "mailto:" that address. Or make a
real product where you can instantiate an "instant" job board. (hint: you'll need to
create another class for this. An "Object Manager" subclass, to be exact.) Or better
yet, make a different app altogether. Check the Zope.org site for user contributed
products and howtos. There's quite a few. :-)
Good luck and above all, have fun!
8.0 Appendix
Over the months that this Howto has been published, a fair number
of folks have written in with comments and questions and thanks.
So, I'd like to express my gratitude here to all those who have written
in - you've all made this howto that much better. Cheers!