[Checkins] SVN: grok/branches/luciano-tutorial/doc/ refactored chapter "Containers", including content about class annotations from removed chapters

Luciano Ramalho luciano at ramalho.org
Fri Jul 13 13:52:18 EDT 2007


Log message for revision 77880:
  refactored chapter "Containers", including content about class annotations from removed chapters
  

Changed:
  U   grok/branches/luciano-tutorial/doc/groktut/containers/src/pebbles/app.py
  D   grok/branches/luciano-tutorial/doc/groktut/containers/src/pebbles/app_templates/giftindex.pt
  U   grok/branches/luciano-tutorial/doc/groktut/containers/src/pebbles/app_templates/index.pt
  A   grok/branches/luciano-tutorial/doc/groktut/containers/src/pebbles/app_templates/mammothdetails.pt
  U   grok/branches/luciano-tutorial/doc/tutorial.txt

-=-
Modified: grok/branches/luciano-tutorial/doc/groktut/containers/src/pebbles/app.py
===================================================================
--- grok/branches/luciano-tutorial/doc/groktut/containers/src/pebbles/app.py	2007-07-13 17:09:29 UTC (rev 77879)
+++ grok/branches/luciano-tutorial/doc/groktut/containers/src/pebbles/app.py	2007-07-13 17:52:17 UTC (rev 77880)
@@ -2,25 +2,25 @@
 
 class Pebbles(grok.Application, grok.Container):
 
-    def receive(self, source, quantity):
-        self[source] = Entry(source, quantity)
+    def addMammoth(self, name, weight):
+        self[name] = Mammoth(name, weight)
     
         
 class Index(grok.View):
     grok.context(Pebbles)
 
-    def update(self, source=None, quantity=0):
-        if description is None:
+    def update(self, name=None, weight=0):
+        if name is None:
             return
-        self.context.receive(source, quantity)
+        self.context.addMammoth(name, weight)
         self.redirect(self.url('index'))
 
 
-class Gift(grok.Model):
-    def __init__(self, source, quantity):
-        self.source = source
-        self.quantity = quantity
+class Mammoth(grok.Model):
+    def __init__(self, name, weight):
+        self.name = name
+        self.weight = weight
 
-class GiftIndex(grok.View):
-    grok.context(Gift)
+class MammothDetails(grok.View):
+    grok.context(Mammoth)
     grok.name('index')

Deleted: grok/branches/luciano-tutorial/doc/groktut/containers/src/pebbles/app_templates/giftindex.pt
===================================================================
--- grok/branches/luciano-tutorial/doc/groktut/containers/src/pebbles/app_templates/giftindex.pt	2007-07-13 17:09:29 UTC (rev 77879)
+++ grok/branches/luciano-tutorial/doc/groktut/containers/src/pebbles/app_templates/giftindex.pt	2007-07-13 17:52:17 UTC (rev 77880)
@@ -1,8 +0,0 @@
-<html>
-<head>
-</head>
-<body>
-  <h2>Gift from <span tal:replace="python:context.__name__"></span></h2>
-  <p><span tal:replace="context/quantity">999</span> stones.</p>
-</body>
-</html>

Modified: grok/branches/luciano-tutorial/doc/groktut/containers/src/pebbles/app_templates/index.pt
===================================================================
--- grok/branches/luciano-tutorial/doc/groktut/containers/src/pebbles/app_templates/index.pt	2007-07-13 17:09:29 UTC (rev 77879)
+++ grok/branches/luciano-tutorial/doc/groktut/containers/src/pebbles/app_templates/index.pt	2007-07-13 17:52:17 UTC (rev 77880)
@@ -2,7 +2,7 @@
 <head>
 </head>
 <body>
-  <h2>Existing gifts</h2>
+  <h2>Mammoths</h2>
   <ul>
     <li tal:repeat="key context/keys">
       <a tal:attributes="href python:view.url(key)" 
@@ -10,11 +10,11 @@
     </li>
   </ul>
  
-  <h2>Receive a gift</h2>
+  <h2>New mammoth</h2>
   <form tal:attributes="action view/url" method="POST">
-    Name: <input type="text" name="source" value="" /><br />
-    Text: <input type="text" name="quantity" value="" /><br />
-    <input type="submit" value="Add gift" />
+    Name: <input type="text" name="name" value="" /><br />
+    Weight: <input type="text" name="weight" value="" /><br />
+    <input type="submit" value="Add mammoth" />
   </form>
 
 </body>

Added: grok/branches/luciano-tutorial/doc/groktut/containers/src/pebbles/app_templates/mammothdetails.pt
===================================================================
--- grok/branches/luciano-tutorial/doc/groktut/containers/src/pebbles/app_templates/mammothdetails.pt	                        (rev 0)
+++ grok/branches/luciano-tutorial/doc/groktut/containers/src/pebbles/app_templates/mammothdetails.pt	2007-07-13 17:52:17 UTC (rev 77880)
@@ -0,0 +1,8 @@
+<html>
+<head>
+</head>
+<body>
+  <h2>Mammoth "<span tal:replace="python:context.name"></span>"</h2>
+  <p>Weight: <span tal:replace="context/weight">999</span> stones.</p>
+</body>
+</html>

Modified: grok/branches/luciano-tutorial/doc/tutorial.txt
===================================================================
--- grok/branches/luciano-tutorial/doc/tutorial.txt	2007-07-13 17:09:29 UTC (rev 77879)
+++ grok/branches/luciano-tutorial/doc/tutorial.txt	2007-07-13 17:52:17 UTC (rev 77880)
@@ -1228,41 +1228,74 @@
 
 Here is the ``app.py`` of our new application:
 
-.. include:: groktut/containers/src/sample/app.py
+.. include:: groktut/containers/src/pebbles/app.py
   :literal:
 
-As you can see, ``Sample`` is unchanged. We have also created our
-first non-application object, ``Entry``. It is just a
-``grok.Model``. It needs to be created with an argument ``text`` and
-this text is stored in it. We intend to place instances of ``Entry``
-in our ``Sample`` container.
+As you can see, ``Pebbles`` is unchanged (XXX really? this needs to be checked). We have also created our
+first non-application model, ``Mammoth``, a subclass of
+``grok.Model``. It needs to be created with the arguments ``name`` and
+weight, which are stored in it. We intend to place instances of ``Mammoth``
+in our ``Pebbles`` container, using the ``name`` as key. 
 
-Next are the views. We have an ``index`` page for the ``Sample``
+Next are the views. For the first time we have two models in the same module, so we need to explicitly declare which views belong to each model. This is done using ``grok.context`` to associate the
+views with models. We actually *have* to do this here, as Grok refuses
+to guess in the face of ambiguity. Without the use of
+``grok.context(Pebbles)`` in the ``Index`` view, we would have seen an error like this when we start
+up Zope::
+
+  GrokError: Multiple possible contexts for <class
+  'pebbles.app.Index'>, please use grok.context.
+
+So, we use ``grok.context`` to explicitly associate ``Index``
+with the ``Pebbles`` application, and again to associate
+``MammothDetails`` with the ``Mammoth`` model.
+
+We have given each template the same name as the corresponding view class, only lowercased. That is how Grok associates them.
+
+We have another problem: the intent is for both views to be ``index``
+views, that is, default views for the models they represent. So far we have achieved this by calling the default view class ``Index``, but in this module we want two default view classes, one for each model, and they cannot have the same name. To tell Grok that the ``MammothDetails`` class is also a default view, we must use a class annotation: `grok.name('index')``. Class annotations are declarative statements which tell grok something about a Python class. 
+
+..sidebar: 
+   Everything that Grok does implicitly can be overridden. Sometimes you 
+   need (or want) to tell Grok what to do, to change its default behavior. 
+   That is why class annotations are needed. For example, do make a turn
+   view into the default, regerdless if the class name, we use the
+   ``grok.name('index')`` class annotation. To associate a view with a
+   specific model, we use ``grok.context(ModelName)``.
+
+So we called the second template ``MammothDetails`` and used the class annotation ``grok.name('index')`` to make it the default view for ``Mammoth``.
+
+We have an ``index`` page for the ``Pebbles``
 container. When its ``update()`` is triggered with two values,
-``name`` and ``text``, it will create a new ``Entry`` instance with
-the given text, and place it under the container under the name
-``name``. We use the dictionary-like interface of our ``Sample``
-container to put our new ``Entry`` in the container.
+``name`` and ``weight``, it will create a new ``Mammoth`` instance with
+the given data, and place it under the container under the name
+``name``. We use the dictionary-like interface of our ``Pebbles``
+container to put our new ``Mammoth`` in the container.
 
-Here is the associated template for ``SampleIndex``, ``sampleindex.pt``:
+Here is the associated template for ``MammothDetails``, ``mammothdetails.pt``:
 
-.. include:: groktut/containers/src/sample/app_templates/sampleindex.pt
+.. include:: groktut/containers/src/pebbles/app_templates/mammothdetails.pt
   :literal:
 
-The first section in the template (``<h2>Existing entries</h2>``)
+The first section in the template (``<h2>Mammoths</h2>``)
 displays a list of the items in the container. We again use
-dictionary-like access using ``keys()`` to get a list of all the names
+dictionary-like access using ``context/keys`` to get a list of all the names
 of the items in the container. We create a link to these items using
-``view.url()``.
+``view/url``.
 
-The next section (``<h2>Add a new entry</h2>``) displays a simple form
+.. sidebar: ZPT: Python and path expressions
+
+  In the TAL syntax of Zope Page Templates, the expression
+  "python:container.keys()" can be written simply as "container/keys"
+  using the path syntax. 
+
+The next section (``<h2>New mammoth</h2>``) displays a simple form
 that submits to the index page itself. It has two fields, ``name`` and
-``text``, which we already have seen handled by ``update()``.
+``weight``, which we already have seen handled by ``update()``.
 
-Finally, we have an ``index`` page for ``Entry``. It just has a template
-to display the ``text`` attribute:
+Finally, we have an ``index`` page for ``Mammoth``. It displays the ``Mammoth`` attributes ``name`` and ``weight``:
 
-.. include:: groktut/containers/src/sample/app_templates/entryindex.pt
+.. include:: groktut/containers/src/pebbles/app_templates/mammothdetails.pt
   :literal:
 
 Restart Zope and try this application.  Call your application
@@ -1272,14 +1305,23 @@
 
   http://localhost:8080/test
 
-When we create an entry called ``hello`` in the form, and then click on it
+When we create a mammoth called "Manfred" in the form, and then click on it
 in the list, you see an URL that looks like this:
 
-  http://localhost:8080/test/hello
+  http://localhost:8080/test/Manfred
 
-We are now looking at the index page of the instance of ``Entry``
-called ``hello``.
+We are now looking at the index page of the instance of ``Mammoth``
+called "Manfred".
 
+We can see that the introduction of a second model has complicated our
+code a bit, though you will hopefully agree with us that it is still
+quite readable. We could have avoided the whole problem by simply
+placing ``Mammoth`` and its views in another module such as
+``mammoth.py``.  Its associated templates would then need to be placed
+in a directory ``mammoth_templates``. Often you will find it possible
+to structure your application so you can use Grok's default
+conventions and avoid using ``grok.context()`` annotations.
+
 What kind of extensions to this application can we think of? We could
 create an ``edit`` form that allows you to edit the text of
 entries. We could modify our application so that you can not just add
@@ -1288,106 +1330,5 @@
 management system with Grok.
 
 
-????????????????????????????????
 
-Explicitly associating a view with a model
-------------------------------------------
 
-Everything that Grok does implicitly you can also tell Grok to do
-explicitly. This will come in handy later, as you may sometimes need
-(or want) to tell Grok what to do, overriding its default behavior. To
-associate a view with a model automatically, you use the
-``grok.context`` class annotation.
-
-What is a class annotation? A class annotation is a declarative way
-to tell grok something about a Python class. Let's look at an example.
-We will change ``app.py`` in the example from `A second view` to demonstrate
-the use of ``grok.context``:
-
-.. include:: groktut/explicitly_associating_a_view_with_a_model/src/sample/app.py
-  :literal:
-
-This code behaves in exactly the same way as the previous example in
-`A second view`, but has the relationship between the model and the
-view made explicit, using the ``grok.context`` class annotation.
-
-``grok.context`` is just one class annotation out of many. We will see
-another one (``grok.name``) in the next section.
-
-A second model
---------------
-
-.. sidebar:: How to combine models into a single application?
-
-  Curious now about how to combine models into a single application?
-  Can't wait? Look at the section `Containers` coming up next, or
-  `Traversal` later on.
-
-We will now extend our application with a second model. Since we
-haven't explained yet how to combine models together into a single
-application, we will just create a second application next to our
-first one. Normally we probably wouldn't want to define two
-applications in the same module, but we are trying to illustrate a few
-points, so please bear with us. Change ``app.py`` so it looks like
-this:
-
-.. include:: groktut/a_second_model/src/sample/app.py
-  :literal:
-
-You can see we now defined a second application class, ``Another``.
-It subclasses from ``grok.Application`` to make it an installable
-application.  
-
-It also subclasses from ``grok.Model``. There is a difference between
-``grok.Model`` and ``grok.Container``, but for the purpose of the
-discussion we can ignore it for now. We just figured we should use
-``grok.Model`` for some variety, though we could have indeed
-subclassed from ``grok.Container`` instead.
-
-We also define two templates, one called ``sampleindex.pt``:
-
-.. include:: groktut/a_second_model/src/sample/app_templates/sampleindex.pt
-  :literal:
-
-And one called ``anotherindex.pt``:
-
-.. include:: groktut/a_second_model/src/sample/app_templates/anotherindex.pt
-  :literal:
-
-We have named the templates the name as the lowercased class names as
-the views, so that they get associated with them.
-
-You will have noticed we have used ``grok.context`` to associate the
-views with models. We actually *have* to do this here, as Grok refuses
-to guess in the face of ambiguity. Without the use of
-``grok.context``, we would have seen an error like this when we start
-up Zope::
-
-  GrokError: Multiple possible contexts for <class
-  'sample.app.AnotherIndex'>, please use grok.context.
-
-So, we use ``grok.context`` to explicitly associate ``SampleIndex``
-with the ``Sample`` application, and again to associate
-``AnotherIndex`` with the ``Another`` application.
-
-We have another problem: the intent is for these views to be ``index``
-views. This cannot be deduced automatically from the name of the view
-classes however, and left to its own devices, Grok would have called
-the views ``sampleindex`` and ``anotherindex``. 
-
-Luckily we have another class annotation that can help us here:
-``grok.name``. We can use it on both view classes
-(``grok.name('index')``) to explicitly explain to Grok what we want.
-
-You can now try to restart Zope and create both applications. They
-should display the correct index pages when you look at them.
-
-We can see that the introduction of a second model has complicated our
-code a bit, though you will hopefully agree with us that it is still
-quite readable. We could have avoided the whole problem by simply
-placing ``Another`` and its views in another module such as
-``another.py``.  Its associated templates would then need to be placed
-in a directory ``another_templates``. Often you will find it possible
-to structure your application so you can use Grok's default
-conventions.
-



More information about the Checkins mailing list