The PEAK Developers' Center   Diff for "IntroToPeak/LessonTwo" UserPreferences
 
HelpContents Search Diffs Info Edit Subscribe XML Print View Up
Ignore changes in the amount of whitespace

Differences between version dated 2003-12-09 22:05:29 and 2005-02-02 05:16:17 (spanning 8 versions)

Deletions are marked like this.
Additions are marked like this.

 
= Lesson Two: Domain Models and Data Retrieval =
 
Now its time to go a tiny step beyond the triviality of the "Hello,
Now it's time to go a tiny step beyond the triviality of the "Hello,
world!" example. In this chapter I'll expand the example to handle
saying hello to an arbitrary variety of things. Since we want to
be flexible. we'll get the greeting message for each thing from a

 
}}}
 
== Application Structure: Moving to a Package ==
 
We're about to complicate our code. In this application, everything
is simple enough we could keep everything in a single `helloworld.py`
file. However, in a PEAK application of any non-trivial size, you
probably won't want to do that. Instead, it generally works best
to group parts of the application that are logically related into
separate files. We'll use that structure for our example even
though it will seem a bit silly because of the small amount of code
involved. But doing it this way will have the advantage that
our configuration exmaples will look more like what you'd use in a
full blown application.
 
So, we'll create a directory `helloworld' that will hold our
application modules. This directory will then need to be on the
python path, and have an `__init__.py` file so that it is a python
package. Since we now have a package called `helloworld`, it is
redundent to have a `helloworld.py` module. Let's rename that
module to something more descriptive of its contents. We'll call
it `commands.py`.
 
To accomodate this change to a package, we need to change our
`hello` ini file as follows: {{{
#!/usr/bin/env peak runIni
 
[peak.running]
 
app = importString('helloworld.commands:HelloWorld')
 
[helloworld]
 
message = "Hello, %s. How are you today?"
}}}
 
So, from this point forward we'll assume you have a properly set
up package directory, and you've put that directory in your PYTHONPATH
via one of the methods described in the previous chapter.
 
 
== Domain Models ==
 
When working with application data, PEAK uses the concept of a "domain model"

to other kinds of objects. In PEAK-speak, the objects are called
"Elements", and the relationships are called "Features". Features are
implemented as object attributes, using custom descriptors.
See the GraphvizTutorial for more info on Domain Models.
 
To facilitate grabbing data from our database, we'll define a simple
Element class, in a `hello_model.py` file: {{{
Element class, in a `model.py` file in our helloworld package: {{{
#!python
from peak.api import *
 

`Message` objects will have once loaded. I think their purposes
should be pretty obvious.
 
You probably noticed immediatly that we are defining classes inside
You probably noticed immediately that we are defining classes inside
classes here. The nested classes actually create attribute descriptors,
similar to the Python built-in `property` type. However, instead of
having to define functions and then wrap them into `property` object,

will construct an appropriately qualified filename for the second
argument based on the assumption that it is in the same directory
as the module named by the first argument. So, `messagefile` will
be the path to the `hello.list` file, located in the same directory
as our `helloworld.py` file.
be the path to the `hello.list` file, located in our `helloworld`
package directory (a package is also a module from python's point
of view). In a real application you probably wouldn't keep a
database file in your package directory, but it's convenient for
us to do so in this example to keep all the files together.
 
Since we're only using a `QueryDM` in this example, we only have
to worry about reading data from the datastore, not writing it

 
world | Hello, world!
Fred | Greetings, good sir.
Klause | Guten Aben, Herr Klause.
Klause | Guten Abend, Herr Klause.
 
}}} (Forgive my feeble attempts at Deutsche.)
}}} (Forgive my feeble attempts at Deutsch.)
 
Because this is going to be a read-only file, we're going to cheat and
load the file only once, the first time it's used. We'll use another

immediately available for use, and won't be computed again for that instance
unless the attribute is deleted.
 
(Of course, in the case of our current `hello` program, we'll only
Of course, in the case of our current `hello` program, we'll only
ever make one query on the database. If we were going to make a
longer-running program, or allow the database to be modified, using
this sort of caching might be a bad idea. However, this design
decision affects only our data manager's implementation, and not the
rest of the application. Our main, command-line application will not
be affected, and neither will our `Message` class, if we decide to change
how or where the messages are stored.)
how or where the messages are stored.
 
=== Building the Data Manager subclass ===
 
Here's the complete contents of the last new file we need for our
expanded `hello` application, the `hello_storage.py` file. This also adds the
expanded `hello` application, the `storage.py` file. This also adds the
`_load` method to the `QueryDM`: {{{
#!python
from peak.api import *
from hello_model import Message
from helloworld.model import Message
 
class MessageDM(storage.QueryDM):
 

program: {{{
#!python
from peak.api import *
from hello_model import Message
from helloworld.model import Message
 
class HelloWorld(commands.AbstractCommand):
 
    Messages = binding.Make(
        'hello_storage.MessageDM',
        'helloworld.storage.MessageDM',
        offerAs=[storage.DMFor(Message)]
    )
 

% ./hello Fred
Greetings, good sir.
% ./hello Klause
Guten Aben, Herr Klause.
Guten Abend, Herr Klause.
 
}}}
 

PythonPowered
ShowText of this page
EditText of this page
FindPage by browsing, title search , text search or an index
Or try one of these actions: AttachFile, DeletePage, LikePages, LocalSiteMap, SpellCheck