[Checkins] SVN: grok/trunk/doc/ Change extension of some doc file into .rst

Jan-Wijbrand Kolman janwijbrand at gmail.com
Thu May 1 06:22:29 EDT 2008


Log message for revision 85970:
  Change extension of some doc file into .rst

Changed:
  A   grok/trunk/doc/about.rst
  D   grok/trunk/doc/about.txt
  A   grok/trunk/doc/naming_conventions.rst
  D   grok/trunk/doc/naming_conventions.txt
  A   grok/trunk/doc/tutorial.rst
  D   grok/trunk/doc/tutorial.txt

-=-
Copied: grok/trunk/doc/about.rst (from rev 85968, grok/trunk/doc/about.txt)
===================================================================
--- grok/trunk/doc/about.rst	                        (rev 0)
+++ grok/trunk/doc/about.rst	2008-05-01 10:22:28 UTC (rev 85970)
@@ -0,0 +1,137 @@
+======================================
+Grok: now even cavemen can use Zope 3
+======================================
+
+Grok is a web application framework for Python developers. It is aimed
+at both beginners and very experienced web developers. Grok has an
+emphasis on agile development. Grok is easy *and* powerful.
+
+Grok: Experience, Expertise, Extensibility
+------------------------------------------
+
+You will likely have heard about many different web frameworks for
+Python as well as other languages. Why you should you consider Grok?
+
+* Grok offers a *lot* of building blocks for your web application.
+
+* Grok is informed by a *lot* of hard-earned wisdom.
+
+Grok accomplishes this by being based on Zope 3, an advanced
+object-oriented web framework. While Grok is based on Zope 3, and
+benefits a lot from it, you do not need to know Zope at all in order
+to get productive with Grok.
+
+Grok is agile
+.............
+
+Grok doesn't require you to edit cryptic configuration files. Instead
+you just program in Python and create HTML templates. Beyond this,
+Grok also offers a wide range of built-in features at your fingertips,
+from automated form generation to an object database. This way, Grok
+gives you both power and quick satisfaction during development. Grok
+is *fun*.
+
+Grok has an extensive tutorial_ that helps you to get started. And
+thanks to grokproject_, you'll be able to create your first web app
+with Grok in no time.
+
+.. _tutorial: /tutorial.html
+
+.. _grokproject: http://cheeseshop.python.org/pypi/grokproject
+
+Grok offers a very wide range of features
+.........................................
+
+Through Zope 3, Grok offers a very wide range of building blocks for
+your web application. What's more, Zope 3 components are typically
+rock-solid due to extensive unit-testing and well-specified API
+documentation.
+
+Grok is grounded in a deep experience with web development
+..........................................................
+
+Grok, through Zope 3, is informed by hard-earned wisdom. Zope 3 is a
+powerful and flexible web application framework for Python that has
+been under continuous development since 2001.  Zope 3's design in turn
+is based on experience with the Zope 2 platform, which has been under
+continuous development (starting with Bobo, Principia and then Zope 1)
+since 1997. The Zope community is supported by an independent
+foundation, the Zope Foundation. 
+
+The Zope community has been around for a while. We've built a lot and
+learned a lot. We are in this for the long run.
+
+Grok for the future
+...................
+
+Successful web applications aren't built for a day - such an
+application will need to be maintained, extended, evolved, over a
+period of many years. Zope developers really know this. Grok, through
+Zope 3, offers an architecture that enables your application to grow
+over time.
+
+
+Grok: Zope 3 for cavemen
+------------------------
+
+Grok stands on a giant's shoulder. That giant is Zope 3.
+
+Zope 3 is an advanced object oriented web framework. Zope 3 features a
+large amount of API documentation and aims for reliability. It has a
+very large automatic test coverage (many thousands of tests). It has a
+large set of core features, and sports an enormous range of plug-in
+components.
+
+The Grok developers think Zope 3 is great. Zope 3, unfortunately, also
+has some problems: its power raises the entry barrier for developers
+to get up to speed with it. Even after you've learned it, Zope 3's
+emphasis on explicit configuration and specification of interfaces can
+slow down development.
+
+Grok aims to remedy these problems. Grok aims to make Zope 3 easier to
+learn, and more agile to work with, while retaining the power of Zope
+3.
+
+Grok appeals to the caveman or woman in all of us. Cavemen, like us
+programmers, want powerful and flexible tools. Cavemen are great at
+tools after all; they invented the whole concept of them. But cavemen,
+and we, also want our tools to be simple and effective.
+
+Cavemen want tools like clubs: a club is powerful, flexible (you can
+bash in anything, mash potatoes too) and also simple and
+effective. Zope 3 is already powerful and flexible. Grok aims to make
+it simpler and more effective, for beginners and experienced
+developers alike. Grok: now even cavemen can use Zope 3.
+
+Grok from the Zope 3 perspective
+--------------------------------
+
+Zope 3 allows you to combine different components in an explicit,
+flexible way. You can hook up a view to a model, an event handler to
+an event, and a new API to an existing object. The process of doing
+this is called *configuration*. In a technical sense, Grok can be
+understood as an alternate configuration mechanism for Zope 3.
+
+Zope 3 without Grok uses ZCML for hooking up objects together. ZCML is
+an XML-based configuration language. ZCML statements are stored in
+their own file, next to the code. While using ZCML has the benefit of
+being explicit and flexible, it can also make code harder to read as
+there are more files to consult in order to understand what is going
+on.
+
+Grok does away with ZCML. Instead it analyzes your Python code for the
+use of certain special base classes and directives, and then "groks"
+it. This grokking process results in the same configuration as it
+would have if you used the equivalent ZCML. We believe that having all
+configuration along with your Python code makes the code easier to
+follow and more fun to develop.
+
+Grok has been designed so that if you organize your code in a certain
+way, you can even leave out most of the explicit directives in your
+Python code. This makes code written for Grok look clean and
+uniform. You still have all the power of explicit configuration
+available should you need it, however.
+
+During the development of Grok we have taken a careful look at common
+patterns in Zope 3 code and configuration. Grok aims to make these
+patterns easier to use and more succinct.

Deleted: grok/trunk/doc/about.txt
===================================================================
--- grok/trunk/doc/about.txt	2008-05-01 10:16:53 UTC (rev 85969)
+++ grok/trunk/doc/about.txt	2008-05-01 10:22:28 UTC (rev 85970)
@@ -1,137 +0,0 @@
-======================================
-Grok: now even cavemen can use Zope 3
-======================================
-
-Grok is a web application framework for Python developers. It is aimed
-at both beginners and very experienced web developers. Grok has an
-emphasis on agile development. Grok is easy *and* powerful.
-
-Grok: Experience, Expertise, Extensibility
-------------------------------------------
-
-You will likely have heard about many different web frameworks for
-Python as well as other languages. Why you should you consider Grok?
-
-* Grok offers a *lot* of building blocks for your web application.
-
-* Grok is informed by a *lot* of hard-earned wisdom.
-
-Grok accomplishes this by being based on Zope 3, an advanced
-object-oriented web framework. While Grok is based on Zope 3, and
-benefits a lot from it, you do not need to know Zope at all in order
-to get productive with Grok.
-
-Grok is agile
-.............
-
-Grok doesn't require you to edit cryptic configuration files. Instead
-you just program in Python and create HTML templates. Beyond this,
-Grok also offers a wide range of built-in features at your fingertips,
-from automated form generation to an object database. This way, Grok
-gives you both power and quick satisfaction during development. Grok
-is *fun*.
-
-Grok has an extensive tutorial_ that helps you to get started. And
-thanks to grokproject_, you'll be able to create your first web app
-with Grok in no time.
-
-.. _tutorial: /tutorial.html
-
-.. _grokproject: http://cheeseshop.python.org/pypi/grokproject
-
-Grok offers a very wide range of features
-.........................................
-
-Through Zope 3, Grok offers a very wide range of building blocks for
-your web application. What's more, Zope 3 components are typically
-rock-solid due to extensive unit-testing and well-specified API
-documentation.
-
-Grok is grounded in a deep experience with web development
-..........................................................
-
-Grok, through Zope 3, is informed by hard-earned wisdom. Zope 3 is a
-powerful and flexible web application framework for Python that has
-been under continuous development since 2001.  Zope 3's design in turn
-is based on experience with the Zope 2 platform, which has been under
-continuous development (starting with Bobo, Principia and then Zope 1)
-since 1997. The Zope community is supported by an independent
-foundation, the Zope Foundation. 
-
-The Zope community has been around for a while. We've built a lot and
-learned a lot. We are in this for the long run.
-
-Grok for the future
-...................
-
-Successful web applications aren't built for a day - such an
-application will need to be maintained, extended, evolved, over a
-period of many years. Zope developers really know this. Grok, through
-Zope 3, offers an architecture that enables your application to grow
-over time.
-
-
-Grok: Zope 3 for cavemen
-------------------------
-
-Grok stands on a giant's shoulder. That giant is Zope 3.
-
-Zope 3 is an advanced object oriented web framework. Zope 3 features a
-large amount of API documentation and aims for reliability. It has a
-very large automatic test coverage (many thousands of tests). It has a
-large set of core features, and sports an enormous range of plug-in
-components.
-
-The Grok developers think Zope 3 is great. Zope 3, unfortunately, also
-has some problems: its power raises the entry barrier for developers
-to get up to speed with it. Even after you've learned it, Zope 3's
-emphasis on explicit configuration and specification of interfaces can
-slow down development.
-
-Grok aims to remedy these problems. Grok aims to make Zope 3 easier to
-learn, and more agile to work with, while retaining the power of Zope
-3.
-
-Grok appeals to the caveman or woman in all of us. Cavemen, like us
-programmers, want powerful and flexible tools. Cavemen are great at
-tools after all; they invented the whole concept of them. But cavemen,
-and we, also want our tools to be simple and effective.
-
-Cavemen want tools like clubs: a club is powerful, flexible (you can
-bash in anything, mash potatoes too) and also simple and
-effective. Zope 3 is already powerful and flexible. Grok aims to make
-it simpler and more effective, for beginners and experienced
-developers alike. Grok: now even cavemen can use Zope 3.
-
-Grok from the Zope 3 perspective
---------------------------------
-
-Zope 3 allows you to combine different components in an explicit,
-flexible way. You can hook up a view to a model, an event handler to
-an event, and a new API to an existing object. The process of doing
-this is called *configuration*. In a technical sense, Grok can be
-understood as an alternate configuration mechanism for Zope 3.
-
-Zope 3 without Grok uses ZCML for hooking up objects together. ZCML is
-an XML-based configuration language. ZCML statements are stored in
-their own file, next to the code. While using ZCML has the benefit of
-being explicit and flexible, it can also make code harder to read as
-there are more files to consult in order to understand what is going
-on.
-
-Grok does away with ZCML. Instead it analyzes your Python code for the
-use of certain special base classes and directives, and then "groks"
-it. This grokking process results in the same configuration as it
-would have if you used the equivalent ZCML. We believe that having all
-configuration along with your Python code makes the code easier to
-follow and more fun to develop.
-
-Grok has been designed so that if you organize your code in a certain
-way, you can even leave out most of the explicit directives in your
-Python code. This makes code written for Grok look clean and
-uniform. You still have all the power of explicit configuration
-available should you need it, however.
-
-During the development of Grok we have taken a careful look at common
-patterns in Zope 3 code and configuration. Grok aims to make these
-patterns easier to use and more succinct.

Copied: grok/trunk/doc/naming_conventions.rst (from rev 85968, grok/trunk/doc/naming_conventions.txt)
===================================================================
--- grok/trunk/doc/naming_conventions.rst	                        (rev 0)
+++ grok/trunk/doc/naming_conventions.rst	2008-05-01 10:22:28 UTC (rev 85970)
@@ -0,0 +1,33 @@
+Grok naming conventions
+-----------------------
+
+Zope 3 used to follow PEP 8, but then PEP 8 changed so that
+methodNames() is deprecated in favor of method_names().
+
+Grok aims to be mostly consistent with Zope 3, but does make some
+changes in the direction of PEP 8.
+
+modulenames - module and package names are all lower case, no
+underscores
+              
+ClassNames - CamelCase (Zope 3 + PEP 8)
+
+methodNames - camelCase: follow Zope 3 conventions. We work a lot with Zope 3
+              classes and sometimes subclass.
+
+attribute_names - Zope 3 + PEP 8
+
+class_annotations - we break with Zope 3 tradition
+                    (grok.local_utility() versus implementsOnly()). 
+                    This makes class annotations stand out a bit
+                    more and is more consistent with the use of
+                    class-level attribute names for customization
+                    as well (as in formlib).
+
+top_level_functions - Zope 3 uses camel case (getUtility()).  Grok
+                      uses underscores for top-level functions that
+                      define class annotations. Grok internally has also
+                      been using underscores for functions defined
+                      internally. So far we have avoided exposing them
+                      to the outside world. If you need to expose
+                      one of these, bring it up on the grok-dev mailing list.

Deleted: grok/trunk/doc/naming_conventions.txt
===================================================================
--- grok/trunk/doc/naming_conventions.txt	2008-05-01 10:16:53 UTC (rev 85969)
+++ grok/trunk/doc/naming_conventions.txt	2008-05-01 10:22:28 UTC (rev 85970)
@@ -1,33 +0,0 @@
-Grok naming conventions
------------------------
-
-Zope 3 used to follow PEP 8, but then PEP 8 changed so that
-methodNames() is deprecated in favor of method_names().
-
-Grok aims to be mostly consistent with Zope 3, but does make some
-changes in the direction of PEP 8.
-
-modulenames - module and package names are all lower case, no
-underscores
-              
-ClassNames - CamelCase (Zope 3 + PEP 8)
-
-methodNames - camelCase: follow Zope 3 conventions. We work a lot with Zope 3
-              classes and sometimes subclass.
-
-attribute_names - Zope 3 + PEP 8
-
-class_annotations - we break with Zope 3 tradition
-                    (grok.local_utility() versus implementsOnly()). 
-                    This makes class annotations stand out a bit
-                    more and is more consistent with the use of
-                    class-level attribute names for customization
-                    as well (as in formlib).
-
-top_level_functions - Zope 3 uses camel case (getUtility()).  Grok
-                      uses underscores for top-level functions that
-                      define class annotations. Grok internally has also
-                      been using underscores for functions defined
-                      internally. So far we have avoided exposing them
-                      to the outside world. If you need to expose
-                      one of these, bring it up on the grok-dev mailing list.

Copied: grok/trunk/doc/tutorial.rst (from rev 85968, grok/trunk/doc/tutorial.txt)
===================================================================
--- grok/trunk/doc/tutorial.rst	                        (rev 0)
+++ grok/trunk/doc/tutorial.rst	2008-05-01 10:22:28 UTC (rev 85970)
@@ -0,0 +1,1350 @@
+=============
+Grok tutorial
+=============
+
+.. raw:: html
+
+   Also available as <a href="./tutorial.pdf">PDF</a>.
+
+.. contents::
+
+Welcome to the Grok tutorial!
+=============================
+
+.. sidebar:: Getting started with Zope Page Templates
+
+  You can find introductions and more information about Zope Page
+  Templates (ZPT, sometimes also called TAL) in various places:
+
+    http://plone.org/documentation/tutorial/zpt
+
+    http://wiki.zope.org/ZPT/FrontPage
+
+  Note that some of the information in these introductions may refer
+  to concepts not available in Grok or Zope 3, in particular variables
+  like ``here`` or ``template``. The basic principles will work with
+  Zope 3 (and Grok) however; try reading ``context`` or ``view``
+  instead.
+
+Grok is a powerful and flexible web application framework for Python
+developers.  In this tutorial we will show you the various things you
+can do with Grok, and how Grok can help you build your web
+application. We'll start out simple, and will slowly go to more
+complex usage patterns.
+
+All you're expected to know is the Python programming language and an
+understanding of basic web programming (HTML, forms, URLs). It also
+helps if you are familiar with Zope Page Templates, though most of the
+examples should be fairly obvious if you are already familiar with
+another templating language.
+
+We recommend that beginners follow the tutorial from top to bottom. The
+tutorial is designed to explain important concepts in order and slowly
+builds up from there.
+
+If you are more experienced, or just curious, you may want to skip
+around instead and read the pieces which interest you most. If
+something is unclear, you can always backtrack to previous sections.
+
+Grok is based on Zope 3 and is compatible with Zope 3, but you do not
+need to know Zope 3 (or Zope 2) at all to follow this tutorial. Grok
+builds on existing Zope 3 technology but exposes it in a different way
+to the developer. We believe Grok makes developing with Zope 3
+technology easier and more fun for beginners and experienced
+developers alike.
+
+Getting started with Grok
+=========================
+
+This chapter will help you get up and running with Grok, using the
+``grokproject`` tool. We create a new project with ``grokproject``,
+tell you how to get that project running so you can access it with a
+web browser.
+
+Setting up grokproject
+----------------------
+
+.. sidebar:: Installing ``easy_install``
+
+  If you don't already have ``easy_install`` available, you can find the
+  script to set it up on the `PEAK EasyInstall page`_.
+
+  .. _`PEAK EasyInstall page`: http://peak.telecommunity.com/DevCenter/EasyInstall#installing-easy-install
+
+  You need to download `ez_setup.py`_. Then, you run it like this to
+  install ``easy_install`` into your system Python::
+
+    $ sudo python2.4 ez_setup.py
+
+  .. _`ez_setup.py`: http://peak.telecommunity.com/dist/ez_setup.py
+
+  This will make ``easy_install`` available to you.
+
+  **Note**: Sometimes you have ``easy_install`` installed but you need
+  a newer version of the underlying setuptools infrastructure to make
+  Grok work. You can automatically upgrade setuptools this by doing::
+
+    $ sudo easy_install -U setuptools
+
+Setting up grok on a Unix-like (Linux, Mac OS X) environment is
+easy. 
+
+Let's go through the prerequisites first. You need a computer
+connected to the internet, as Grok installs itself over the
+network. You also need Python 2.4 installed (Python 2.5 is not
+yet supported, and does not pass all unit tests, though some
+have reported success using it with Grok.)
+
+Because Grok uses a source distribution of Zope 3, you may need to
+install your operating system's Python "dev" package. You also need a
+working C compiler (typically ``gcc``) installed, as we compile bits of
+Zope 3 during setup. Finally, you also need ``easy_install`` installed
+so it becomes easy to install eggs.
+
+Once you are done with the prerequisites, you can install
+grokproject itself::
+
+  $ sudo easy_install grokproject
+
+We're ready to create our first grok project now!
+
+Creating a grok project
+-----------------------
+
+Let's create a first Grok project. A Grok project is a working
+environment for a developer using Grok. In essence, a directory with a
+lot of files and subdirectories in it. Let's create a Grok project
+called Sample::
+
+  $ grokproject Sample
+
+This tells grokproject to create a new subdirectory called ``Sample``
+and set up the project in there. grokproject will automatically
+download and install Zope 3 and Grok into the project area.
+
+You will be asked a number of questions now. First you need to supply
+the name of the initial module that your package will contain. We'll
+stick with the default ``app.py``::
+ 
+  Enter module (Name of a demo Python module placed into the package) ['app.py']:
+
+After this Grok asks you for an initial username and password for the
+Zope server. We'll use ``grok`` for both::
+
+  Enter user (Name of an initial administrator user): grok
+  Enter passwd (Password for the initial administrator user): grok
+  Enter eggs_dir (Location where zc.buildout will look for and place packages) ['/home/<user>/buildout-eggs']:
+
+For the last question, we'll stick with the default path which will be
+a directory called 'buildout-eggs' in your home directory.
+
+Now you have to wait while grokproject downloads `zc.buildout`_
+(the system that's used to build the project area), Grok and the Zope
+3 libraries.
+
+After all that, Grok, along with a Zope 3 instance, is ready to go. 
+
+Starting up Zope
+----------------
+
+You can go into the ``Sample`` project directory now and start up the
+Zope instance that has been installed::
+
+  $ cd Sample
+  $ bin/zopectl fg
+
+This will make Zope 3 available on port 8080, and you can log in with
+username ``grok`` and password ``grok``. Assuming you've started up
+Zope on your localhost, you can go to it here:
+
+  http://localhost:8080
+
+This first pops up a login dialog (username: ``grok`` and password:
+``grok``). It will then show a simple Grok admin interface. This
+allows you to install new Grok applications. 
+
+Our sample application (``sample.app.Sample``) will be available for
+adding. Let's try this out.  Go to the Grok admin page:
+
+  http://localhost:8080
+
+and add a Sample application. Give it the name ``test``.
+
+You can now go to the installed application if you click on its link. This
+will bring you to the following URL:
+
+  http://localhost:8080/test
+
+You should see a simple web page with the following text on it::
+
+  Congratulations!
+
+  Your Grok application is up and running. Edit
+  sample/app_templates/index.pt to change this page.
+
+You can shut down Zope 3 at any time by hitting ``CTRL-c``. Shut it
+down now. We will be shutting down and starting up Zope 3 often in
+this tutorial.
+
+Practice restarting Zope now, as you'll end up doing it a lot during
+this tutorial. It's just stopping Zope and starting it again:
+`CTRL-c`` and then ``bin/zopectl fg`` from your Sample
+project directory.
+
+An empty Grok project
+---------------------
+
+.. sidebar:: What about the other directories and files in our project?
+
+  What about the other files and subdirectories in our ``Sample`` project
+  directory? Grokproject sets up the project using a system called
+  `zc.buildout`_. The ``eggs``, ``develop-eggs`` and ``bin``
+  directories are all set up and maintained by zc.buildout. See its
+  documentation for more information about how to use it. The
+  configuration of the project and its dependency is in
+  ``buildout.cfg``. For now, you can avoid these details however.
+
+  .. _`zc.buildout`: http://cheeseshop.python.org/pypi/zc.buildout
+
+Let's take a closer look at what's been created in the Sample project
+directory.
+
+One of the things grokproject created was a ``setup.py`` file. This file
+contains information about your project. This information is used by
+Python distutils and setuptools. You can use the ``setup.py`` file to
+upload your project to the Python Cheeseshop. We will discuss this in
+more detail later in this tutorial. (XXX)
+
+We have already seen the ``bin`` directory. It contains the startup
+script for the Zope instance (``bin/zopectl``) as well as the
+executable for the buildout system (``bin/buildout``) which can be
+used to re-build the Zope instance and possibly update the Grok and
+Zope packages.
+
+The ``parts`` directory contains configuration and data created by
+``buildout``, such as the Zope object database (ZODB) instance.
+
+The actual code of the project will all be inside the ``src``
+directory. In it is a Python package directory called ``sample`` with
+the ``app.py`` file that grokproject said it would create. Let's look
+at this file:
+
+.. include:: groktut/an_empty_grok_project/src/sample/app.py
+   :literal:
+
+Not very much yet, but enough to make an installable Grok application
+and display its welcome page. We'll go into the details of what this
+means later.
+
+Besides this, there is an empty ``__init__.py`` file to make this
+directory a Python package. 
+
+There is also a directory called ``app_templates``. It contains a single
+template called ``index.pt``:
+
+.. include:: groktut/an_empty_grok_project/src/sample/app_templates/index.pt
+  :literal:
+
+This is the template for your project's welcome page.
+
+What's left is a ``configure.zcml`` file. Unlike in typical Zope 3
+applications, this will only ever contain a few lines that load Grok
+and then register this application with Grok. This means we can
+typically completely ignore it, but we'll show it here once for good
+measure:
+
+.. include:: groktut/an_empty_grok_project/src/sample/configure.zcml
+   :literal:
+
+Showing pages
+=============
+
+Showing web pages is what puts the *web* in "web applications". You
+start doing this with HTML templates, but Grok doesn't stop at
+templates. Most web pages in a web application will contain complex
+presentation logic that is better handled by separate Python code in
+conjunction with templates. This becomes especially important in more
+complex interactions with the user, such as form handling. After
+reading this chapter, you should already be able to write simple web
+applications with Grok.
+
+Publishing a simple web page
+----------------------------
+
+Let's publish a simple static web page. Grok is geared towards web
+applications and therefore not really meant for publishing a large
+number of static (pregenerated) web pages. For that you're better off
+to use a specialized system such as Apache. Nonetheless, in order to
+develop any web application we need to know how to put some simple
+HTML on the web.
+
+As you saw previously, our ``Sample`` application has a stock front
+page, generated by grokproject. Let's change that.
+
+To do this, go to the ``app_templates`` directory in ``src/sample/``.
+This directory contains the templates used for anything defined in the
+``app`` module. Grok knows to associate the directory to the module by
+its name (``<module_name>_templates``).
+
+In this directory we will edit the ``index`` template for our
+``Sample`` application object. To do this, open the ``index.pt`` file
+in a text editor. The ``.pt`` extension indicates that this file is a
+Zope Page Template (ZPT). We're just going to put HTML in it now, but
+this allows us to make page dynamic later on.
+
+Change the ``index.pt`` file to contain the following (very
+simplistic) HTML:
+
+.. include:: groktut/publishing_a_simple_web_page/src/sample/app_templates/index.pt
+  :literal:
+
+Then reload the page:
+
+  http://localhost:8080/test
+
+You should now see the following text::
+
+  Hello world!
+
+Note that you can change templates and see the effects instantly:
+there is no need to restart Zope to see the effect. This is not true
+for changes on the Python level, for instance when you add a
+template. We show an example of this next.
+
+A second view
+-------------
+
+Our view is named ``index``. This in fact means something slightly
+special: it's the default view of our application object. We can also
+access it explicitly by naming the view:
+
+  http://localhost:8080/test/index
+
+If you view that URL in your browser, you should see the same result
+as before. This is the way all other, non-index views are accessed.
+
+Often, your application needs more than one view. A document for
+instance may have an ``index`` view that displays it, but another
+``edit`` view to change its contents.  To create a second view, create
+another template called ``bye.pt`` in ``app_templates``. Make it have
+the following content:
+
+.. include:: groktut/a_second_view/src/sample/app_templates/bye.pt
+  :literal:
+
+Now we need to tell Grok to actually use this template. To do this,
+modify ``src/sample/app.py`` so that it reads like this:
+
+.. include:: groktut/a_second_view/src/sample/app.py
+  :literal:
+
+As you can see, all we did was add a class called ``Bye`` that
+subclasses from ``grok.View``. This indicates to Grok that we want a
+view named ``bye`` for the application, just like the ``Index`` class
+that was already created for us indicates that we want a view named
+``index``. A *view* is a way to view some model, in this case
+installations of our ``Sample`` application. Note that the view name
+in the URL is always going to be lowercase, while the class name
+normally starts with an uppercase letter.
+
+The empty class definition above is enough for Grok to go look in the
+``app_templates`` directory for ``bye.pt``. The rule is that a the
+template should have the same name as the class, but lowercased and
+with the ``.pt`` postfix.
+
+Restart Zope (``CTRL-C, then ``bin/zopectl fg``). You can now go to a
+new web page called ``bye``:
+
+  http://localhost:8080/test/bye
+
+When you load this web page in a browser, you should see the following
+text::
+
+  Bye world!
+
+Making our page dynamic
+-----------------------
+
+Static web pages are not very helpful if we want to make a dynamic web
+application. Let's make a page that shows the result of a very simple
+calculation: ``1 + 1``. 
+
+We will use a Zope Page Templates (ZPT) directive to do this
+calculation inside ``index.pt`` template. Change the ``index.pt`` to
+read like this:
+
+.. include:: groktut/making_our_page_dynamic/src/sample/app_templates/index.pt
+  :literal:
+
+We've used the ``tal:content`` page template directive to replace the
+content between the ``<p>`` and ``</p>`` tags with something else, in
+this case the result of the Python expression ``1 + 1``.
+
+Since restarting Zope is not necessary for changes that are limited to
+the page templates, you can just reload the web page:
+
+  http://localhost:8080/test
+
+You should see the following result::
+
+  2
+
+Looking at the source of the web page shows us this::
+
+  <html>
+  <body>
+  <p>2</p>
+  </body>
+  </html>
+
+As you can see, the content of the ``<p>`` tag was indeed replaced
+with the result of the expression ``1 + 1``.
+
+Static resources for our web page
+---------------------------------
+
+In real-world web pages, we almost never publish a web page that just
+contains bare-bones HTML. We also want to refer to other resources,
+such as images, CSS files or Javascript files. As an example, let's
+add some style to our web page.
+
+To do this, create a new directory called ``static`` in the ``sample``
+package (so, ``src/sample/static``). In it, place a file called
+``style.css`` and put in the following content:
+
+.. include:: groktut/static_resources_for_our_web_page/src/sample/static/style.css
+  :literal:
+
+In order to use it, we also need to refer to it from our
+``index.pt``. Change the content of ``index.pt`` to read like this:
+
+.. include:: groktut/static_resources_for_our_web_page/src/sample/app_templates/index.pt
+  :literal:
+
+Now restart Zope and reload the page:
+
+  http://localhost:8080/test
+
+The web page should now show up with a red background.
+
+You will have noticed we used the ``tal:attributes`` directive in our
+``index.pt`` now. This uses Zope Page Templates to dynamically
+generate the link to our file ``style.css``.
+
+Let's take a look at the source code of the generated web page::
+
+  <html>
+  <link rel="stylesheet" type="text/css"
+        href="http://localhost:8080/test/@@/sample/style.css" />
+  <body>
+  <p>Hello world!</p>
+  </body>
+  </html>
+
+As you can see, the ``tal:attributes`` directive is gone and has been
+replaced with the following URL to the actual stylesheet:
+
+  http://localhost:8080/test/@@/sample/style.css
+
+We will not go into the details of the structure of the URL here, but
+we will note that because it's generated this way, the link to
+``style.css`` will continue to work no matter where you install your
+application (i.e. in a virtual hosting setup).
+
+Pulling in images or javascript is very similar. Just place your image
+files and `.js` files in the ``static`` directory, and create the URL
+to them using ``static/<filename>`` in your page template.
+
+Using view methods
+------------------
+
+.. sidebar:: Unassociated templates
+
+  If you have followed the tutorial so far, you will have an extra
+  template called ``bye.pt`` in your ``app_templates`` directory.
+  Since in the given ``app.py``e we have no more class using it, the
+  ``bye.pt`` template will have become *unassociated**. When you try
+  to restart Zope, grok will be unable to read your application, and
+  Zope will crash with an error message like this::
+
+    GrokError: Found the following unassociated template(s) when
+    grokking 'sample.app': bye.  Define view classes inheriting from
+    grok.View to enable the template(s).
+
+  To resolve this error, simply remove ``bye.pt`` from your
+  ``app_templates`` directory.
+
+ZPT is deliberately limited in what it allows you to do with Python.
+It is good application design practice to use ZPT for fairly simple
+templating purposes only, and to do anything a bit more complicated in
+Python code. Using ZPT with arbitrary Python code is easy: you just
+add methods to your view class and use them from your template.
+
+Let's see how this is done by making a web page that displays the
+current date and time. We will use our Python interpreter to find out
+what works::
+
+  $ python
+  Python 2.4.4
+  Type "help", "copyright", "credits" or "license" for more information.
+  >>> 
+
+We will need Python's ``datetime`` class, so let's import it::
+
+  >>> from datetime import datetime
+
+Note that this statement brings us beyond the capabilities of simple
+ZPT use; it is not allowed to import arbitrary Python modules from
+within a ZPT template; only Python *expressions* (with a result) are
+allowed, not *statements* such as ``from .. import ..``.
+
+Let's get the current date and time::
+
+  >>> now = datetime.now()
+
+This gives us a date time object; something like this::
+
+  >>> now
+  datetime.datetime(2007, 2, 27, 17, 14, 40, 958809)
+
+Not very nice to display on a web page, so let's turn it into a
+prettier string using the formatting capabilities of the ``datetime``
+object::
+
+  >>> now.strftime('%Y-%m-%d %H:%M')
+  '2007-02-27 17:14'
+
+That looks better.
+
+So far nothing new; just Python. We will integrate this code into our
+Grok project now. Go to ``app.py`` and change it to read like this:
+
+.. include:: groktut/using_view_methods/src/sample/app.py
+  :literal:
+
+We've simply added a method to our view that returns a string
+representing the current date and time. Now to get this string in our
+page template. Change ``index.pt`` to read like this:
+
+.. include:: groktut/using_view_methods/src/sample/app_templates/index.pt
+  :literal:
+
+Restart Zope. This is needed as we changed the content of a Python
+file (``app.py``). Now reload our index page to see whether it worked:
+
+  http://localhost:8080/test
+
+You should see a web page with a date and time like this on your
+screen now::
+
+  2007-02-27 17:21
+
+What happened here? When viewing a page, the view class (in this case
+``Index`` is instantiated by Zope. The name ``view`` in the template
+is always made available and is associated with this instance. We then
+simply call the method on it in our template.
+
+There is another way to write the template that is slightly shorter
+and may be easier to read in some cases, using a ZPT path expression::
+
+  <html>
+  <body>
+  <p tal:content="view/current_datetime"></p>
+  </body>
+  </html>
+
+Running this has the same result as before.
+
+Generating HTML from Python
+---------------------------
+
+While usually you will be using templates to generate HTML, sometimes
+you want to generate complicated HTML in Python and then include it in
+an existing web page. For reasons of security against cross-site
+scripting attacks, TAL will automatically escape any HTML into `&gt;`
+and `&lt;`. With the ``structure`` directive, you can tell TAL
+explicitly to not escape HTML this way, so it is passed literally into
+the template. Let's see how this is done. Change ``app.pt`` to read like
+this:
+
+.. include:: groktut/generating_html_from_python/src/sample/app.py
+  :literal:
+
+and then change ``index.pt`` to read like the following:
+
+.. include:: groktut/generating_html_from_python/src/sample/app_templates/index.pt
+  :literal:
+
+Let's take another look at our web page:
+
+  http://localhost:8080/test
+
+You should see the following text (in bold):
+
+  **ME GROK BOLD**
+
+This means the HTML we generated from the ``some_html`` method was
+indeed successfully integrated in our web page.  Without the the
+``structure`` directive, you would've seen the following instead::
+ 
+  <b>ME GROK BOLD</b>
+
+Completely Python-driven views
+------------------------------
+
+.. sidebar:: Setting the content-type
+
+  When generating the complete content of a page yourself, it's often
+  useful to change the content-type of the page to something else than
+  ``text/plain``. Let's change our code to return simple XML and set
+  the content type to ``text/xml``:
+
+  .. include:: groktut/setting_the_content_type/src/sample/app.py
+    :literal:
+
+  All views in Grok have a ``response`` property that you can use to
+  manipulate response headers.
+
+Sometimes it is inconvenient to have to use a template at all. Perhaps
+we are not returning a HTML page at all, for instance. In this case,
+we can use the special ``render`` method on a view.
+
+Modify ``app.py`` so it reads like this:
+
+.. include:: groktut/completely_python_driven_views/src/sample/app.py
+  :literal:
+
+If you were to start up Zope with an ``index.pt`` template still
+inside ``app_templates`` you would get an error::
+
+    GrokError: Multiple possible ways to render view <class
+    'sample.app.Index'>. It has both a 'render' method as well as an
+    associated template.
+
+In the face of ambiguity Grok, like Python, refuses to guess. To
+resolve this error, remove ``index.pt`` from the ``app_templates``
+directory.
+
+Now take another look at our test application:
+
+  http://localhost:8080/test
+
+You should see the following::
+
+  ME GROK NO TEMPLATE
+
+You should see this even when you view the source of the page. When
+looking at the content type of this page, you will see that it is
+``text/plain``.
+
+Doing some calculation before viewing a page
+--------------------------------------------
+
+Instead of calculating some values in a method call from the template,
+it is often more useful to calculate just before the web page's
+template is calculated. This way you are sure that a value is only
+calculated once per view, even if you use it multiple times.
+
+You can do this by defining an ``update`` method on the view class. Modify
+``app.py`` to read like this:
+
+.. include:: groktut/doing_some_calculation_before_viewing_a_page/src/sample/app.py
+  :literal:
+
+This sets a name ``alpha`` on the view just before the template is
+being displayed, so we can use it from the template. You can set as
+many names on ``self`` as you like.
+
+Now we need a template ``index.pt`` that uses ``alpha``:
+
+.. include:: groktut/doing_some_calculation_before_viewing_a_page/src/sample/app_templates/index.pt
+  :literal:
+
+Restart Zope and then let's take another look at our application:
+
+  http://localhost:8080/test
+
+You should see 256, which is indeed 2 raised to the power 8.
+
+Reading URL parameters
+----------------------
+
+When developing a web application, you don't just want to output data,
+but also want to use input. One of the simplest ways for a web
+application to receive input is by retrieving information as a URL
+parameter. Let's devise a web application that can do sums for us. In
+this application, if you enter the following URL into that
+application:
+
+  http://localhost:8080/test?value1=3&value2=5
+
+you should see the sum (8) as the result on the page. 
+
+Modify ``app.py`` to read like this:
+
+.. include:: groktut/reading_url_parameters/src/sample/app.py
+  :literal:
+
+We need an ``index.pt`` that uses ``sum``:
+
+.. include:: groktut/reading_url_parameters/src/sample/app_templates/index.pt
+  :literal:
+
+Restart Zope. Now going to the folllowing URL should display 8:
+
+  http://localhost:8080/test?value1=3&value2=5
+
+Other sums work too, of course:
+
+  http://localhost:8080/test?value1=50&value2=50
+
+What if we don't supply the needed parameters (``value1`` and
+``value2``) to the request? We get an error:
+
+  http://localhost:8080/test
+
+You can look at the window where you started up Zope to see the error
+traceback. This is the relevant complaint::
+
+  TypeError: Missing argument to update(): value1
+
+We can modify our code so it works even without input for either parameter:
+
+.. include:: groktut/reading_url_parameters2/src/sample/app.py
+  :literal:
+
+Restart Zope, and see it can now deal with missing parameters (they
+default to ``0``).
+
+Simple forms
+------------
+
+.. sidebar:: Automatic forms
+
+  Creating forms and converting and validating user input by hand, as
+  shown in this section, can be rather cumbersome. With Grok, you can
+  use Zope 3's *schema* and *formlib* systems to automate this and
+  more. This will be discussed in a later section. XXX
+
+Entering the parameters through URLs is not very pretty. Let's use a
+form for this instead. Change ``index.pt`` to contain a form, like
+this:
+
+.. include:: groktut/simple_forms/src/sample/app_templates/index.pt
+  :literal:
+
+One thing to note here is that we dynamically generate the form's
+``action``. We make the form submit to itself, basically. Grok views
+have a special method called ``url`` that you can use to retrieve the
+URL of the view itself (and other URLs which we'll go into later).
+
+Leave the ``app.py`` as in the previous section, for now. You can now
+go to the web page::
+
+  http://localhost:8080/test
+
+You can submit the form with some values, and see the result displayed
+below.
+
+We still have a few bugs to deal with however. For one, if we don't fill
+in any parameters and submit the form, we get an error like this::
+
+  File "../app.py", line 8, in update
+    self.sum = int(value1) + int(value2)
+  ValueError: invalid literal for int(): 
+
+This is because the parameters were empty strings, which cannot be
+converted to integers. Another thing that is not really pretty is that
+it displays a sum (0) even if we did not enter any data. Let's change
+``app.py`` to take both cases into account:
+
+.. include:: groktut/simple_forms2/src/sample/app.py
+  :literal:
+
+We catch any TypeError and ValueError here so that wrong or missing
+data does not result in a failure. Instead we display the text "No
+sum". If we don't get any error, the conversion to integer was fine,
+and we can display the sum.
+
+Restart Zope and go to the form again to try it out:
+
+  http://localhost:8080/test
+
+Models
+======
+
+Now we know how to show web pages, we need to go into what we are
+actually showing: the models. The models contain the
+display-independent logic of your application. In this chapter we will
+discuss a number of issues surrounding models: how your views connect
+to models, and how you can make sure the data in your models is stored
+safely. As the complexity of our sample applications grows, we will
+also go into a few more issues surrounding form handling.
+
+A view for a model
+------------------
+
+So far, we have only seen views that do the work all by themselves.
+In typical applications this is not the case however - views display
+information that is stored elsewhere. In Grok applications, views work
+for models: subclasses of ``grok.Model`` or ``grok.Container``. For
+the purposes of this discussion, we can treat a ``grok.Container`` as
+another kind of ``grok.Model`` (more about what makes
+``grok.Container`` special later XXX).
+
+Our ``Sample`` class is a ``grok.Container``, so let's use ``Sample``
+to demonstrate the basic principle. Let's modify ``app.py`` so that
+``Sample`` actually makes some data available:
+
+.. include:: groktut/a_view_for_a_model/src/sample/app.py
+  :literal:
+
+In this case, the information (``"This is important information!"``)
+is just hardcoded, but you can imagine information is retrieved from
+somewhere else, such as a relational database or the filesystem.
+
+We now want to display this information in our template ``index.pt``:
+
+.. include:: groktut/a_view_for_a_model/src/sample/app_templates/index.pt
+  :literal:
+
+Restart Zope. When you view the page:
+
+  http://localhost:8080/test
+
+You should now see the following::
+
+  This is important information!
+
+Previously we have seen that you can access methods and attributes on
+the view using the special ``view`` name in a template. Similarly, the
+name ``context`` is also available in each template. ``context``
+allows us to access information on the context object the view is
+displaying. In this case this is an instance of ``Sample``, our
+application object.
+
+Separating the model from the view that displays it is an important
+concept in structuring applications. The view, along with the
+template, is responsible for displaying the information and its user
+interface. The model represents the actual information (or content)
+the application is about, such as documents, blog entries or wiki
+pages. The model should not know anything about the way it is
+displayed.
+
+This way of structuring your applications allows you to change the way
+your model is displayed without modifying the model itself, just
+the way it is viewed.
+
+Let's do that by making the view do something to the information. Change 
+``app.py`` again:
+
+.. include:: groktut/a_view_for_a_model2/src/sample/app.py
+  :literal:
+
+You can see that it is possible to access the context object (an
+instance of ``Sample``) from within the view class, by accessing the
+``context`` attribute. This gets the same object as when we used the
+``context`` name in our template before.
+
+What we do here is reverse the string returned from the
+``information()`` method. You can try it on the Python prompt::
+
+  >>> ''.join(reversed('foo'))
+  'oof'
+
+Now let's modify the ``index.pt`` template so that it uses the
+``reversed_information`` method:
+
+.. include:: groktut/a_view_for_a_model2/src/sample/app_templates/index.pt
+  :literal:
+
+Restart Zope. When you view the page:
+
+  http://localhost:8080/test
+
+You should now see the following:
+
+  The information: This is important information!
+
+  The information, reversed: !noitamrofni tnatropmi si sihT 
+
+Storing data
+------------
+
+So far we have only displayed either hardcoded data, or calculations
+based on end-user input. What if we actually want to *store* some
+information, such as something the user entered? The easiest way to do
+this with Zope is to use the Zope Object Database (ZODB).
+
+The ZODB is a database of Python objects. You can store any Python
+object in it, though you do need to follow a few simple rules (the
+"rules of persistence", which we will go into later). Our ``Sample``
+application object is stored in the object database, so we can store
+some information on it.
+
+Let's create an application that stores a bit of text for us. We will
+use one view to view the text (``index``) and another to edit it
+(``edit``).
+
+Modify ``app.py`` to read like this:
+
+.. include:: groktut/storing_data/src/sample/app.py
+  :literal:
+
+The ``Sample`` class gained a class attribute with some default text.
+In the ``update`` method of the ``Edit`` view you can see we actually
+set the ``text`` attribute on the context, if at least a ``text``
+value was supplied by a form. This will set the ``text`` attribute on
+the instance of the ``Sample`` object in the object database, and thus
+will override the default ``text`` class attribute.
+
+Change the ``index.pt`` template to read like this:
+
+.. include:: groktut/storing_data/src/sample/app_templates/index.pt
+  :literal:
+
+This is a very simple template that just displays the ``text``
+attribute of the ``context`` object (our ``Sample`` instance).
+
+Create an ``edit.pt`` template with the following content:
+
+.. include:: groktut/storing_data/src/sample/app_templates/edit.pt
+  :literal:
+
+This template display a form asking for a bit of text. It submits to
+itself.
+
+Restart Zope. Let's first view the index page:
+
+  http://localhost:8080/test
+
+You should see ``default text``.
+
+Now let's modify the text by doing to the edit page of the application:
+
+  http://localhost:8080/test/edit
+
+Type in some text and press the "Store" button. Since it submits to
+itself, we will see the form again, so go to the index page manually:
+
+  http://localhost:8080/test
+ 
+You should now see the text you just entered on the page. This means
+that your text was successfully stored in the object database!
+
+You can even restart Zope and go back to the index page, and your text
+should still be there.
+
+Redirection
+-----------
+
+Let's make our application a bit easier to use. First, let's change
+``index.pt`` so it includes a link to the edit page. To do this, we
+will use the ``url`` method on the view:
+
+.. include:: groktut/redirection/src/sample/app_templates/index.pt
+  :literal:
+
+Giving ``url`` a single string argument will generate a URL to the
+view named that way on the same object (``test``), so in this case
+``test/edit``.
+
+Now let's change the edit form so that it redirects back to the
+``index`` page after you press the submit button:
+
+.. include:: groktut/redirection/src/sample/app.py
+  :literal:
+
+The last line is the new one. We use the ``url`` method on the view to
+construct a URL to the ``index`` page. Since we're in the template, we
+can simply call ``url`` on ``self``. Then, we pass this to another
+special method available on all ``grok.View`` subclasses,
+``redirect``. We tell the system to redirect to the ``index`` page.
+
+Showing the value in the form
+-----------------------------
+
+Let's change our application so it displays what we stored the edit
+form as well, not just on the index page.
+
+To make this work, change edit.pt so it reads like this:
+
+.. include:: groktut/showing_the_value_in_the_form/src/sample/app_templates/edit.pt
+  :literal:
+
+The only change is that we have used ``tal:attributes`` to include the
+value of the ``text`` attribute of the context object in the form.
+
+The rules of persistence
+------------------------
+
+These are the "rules of persistence":
+
+* You should subclass classes that want to store data from
+  ``persistent.Persistent`` so that it's easy to store them in the
+  ZODB. The simplest way to do this with Grok is to subclass from
+  ``grok.Model`` or ``grok.Container``.
+
+* Instances that you want to store should be connected to other
+  persistent classes that are already stored. The simplest way to do
+  this with Grok is to attach them somehow to the ``grok.Application``
+  object, directly or indirectly. This can be done by setting them as
+  an attribute, or by putting them in a container (if you made your
+  application subclass ``grok.Container``).
+
+* To make sure that the ZODB knows you changed a mutable attribute
+  (such as a simple Python list or dictionary) in your instance, set
+  the special ``_p_changed`` attribute on that instance to
+  ``True``. This is only necessary if that attribute is not
+  ``Persistent`` itself. It is also not necessary when you create or
+  overwrite an attribute directly using ``=``.
+
+If you construct your application's content out of ``grok.Model`` and
+``grok.Container`` subclasses you mostly follow the rules
+already. Just remember to set ``_p_changed`` in your methods if you
+find yourself modifying a Python list (with ``append``, for instance)
+or dictionary (by storing a value in it).
+
+The code in the section `Storing data`_ is a simple example. We in
+fact have to do nothing special at all to obey the rules of
+persistence in that case.
+
+If we use a mutable object such as a list or dictionary to store data
+instead, we do need to take special action. Let's change our example
+code (based on the last section) to use a mutable object (a list):
+
+.. include:: groktut/the_rules_of_persistence/src/sample/app.py
+  :literal:
+
+We have now changed the ``Sample`` class to do something new: it has
+an ``__init__`` method. Whenever you create the ``Sample`` application
+object now, it will be created with an attribute called ``list``,
+which will contain an empty Python list. 
+
+We also make sure that the ``__init__`` method of the superclass still
+gets executed, by using the regular Python ``super`` idiom. If we
+didn't do that, our container would not be fully initialized.
+
+You will also notice a small change to the ``update`` method of the
+``Edit`` class. Instead of just storing the text as an attribute of
+our ``Sample`` model, we add each text we enter to the new
+``list`` attribute on. 
+
+Note that this code has a subtle bug in it, which is why we've added
+the comment. We will see what bug this is in a little bit. First,
+though, let's change our templates.
+
+We change ``index.pt`` so that it displays the list:
+
+.. include:: groktut/the_rules_of_persistence/src/sample/app_templates/index.pt
+  :literal:
+
+We've also changed the text of the link to the ``edit`` page to reflect
+the new adding behavior of our application.
+
+We need to undo the change to the ``edit.pt`` template that we
+made in the last section, as each time we edit a text we now *add* a
+new text, instead of changing the original. There is therefore no text
+to show in as the input value anymore:
+
+.. include:: groktut/the_rules_of_persistence/src/sample/app_templates/edit.pt
+  :literal:
+
+.. sidebar:: evolution
+
+  What to do when you change an object's storage structure while your
+  application is already in production? In a later section, we will
+  introduce Zope 3's object evolution mechanism that allows you to
+  update objects in an existing object database. XXX
+
+Let's restart our Zope application. If you have followed the tutorial
+from the last section, you will now see an error when you look at the
+front page of the application::
+
+  A system error occurred. 
+
+Look at the output Zope gave when we tried to load our page::
+
+  AttributeError: 'Sample' object has no attribute 'list'
+
+But we just changed our object to have an attribute ``list``, right?
+Yes we did, but only for *new* instances of the Sample object. What we
+are looking at is the sample object from before, still stored in the
+object database. It has no such attribute. This isn't a bug by the way
+(for our actual bug, see later in this section): it is just a database
+problem.
+
+What to do now? The simplest action to take during development is to
+simply remove our previously installed application, and create a new
+one that *does* have this attribute. Go to the Grok admin screen:
+
+  http://localhost:8080
+
+Select the application object (``test``) and delete it. Now install it
+again, as ``test``. Now go to its edit screen and add a text:
+
+  http://localhost:8080/test/edit
+
+Click on ``add a text`` and add another text. You will see the new
+texts appear on the ``index`` page.
+
+Everything is just fine now, right? In fact, not so! Now we will get
+to our bug. Restart Zope and look at the index page again:
+
+  http://localhost:8080/test
+
+None of the texts we added were saved! What happened? We broke the
+third rule of persistence as described above: we modified a mutable
+attribute and did not notify the database that we made this
+change. This means that the object database was not aware of our
+change to the object in memory, and thus never saved it to disk.
+
+.. sidebar: The ZODB only stores instance data
+
+  Note that the ZODB only stores ("persists") instance data. This
+  means that any data you have directly associated with a class, as
+  opposed to the instance, won't be persisted. Normally you only
+  associate immutable data with the class, so this is not a problem::
+ 
+    class Foo(object):
+        mydata = 'some text'
+
+  That data will be there when the module is imported, and since it 
+  will never be changed, there isn't a problem. Now let's check what
+  happens with mutable data::
+
+    class Foo(object):
+        mydata = []
+
+  Appending an item to mydata (through ``self.mydata.append('bar')``,
+  for instance) have an effect, but only until you restart Zope. Then
+  your changes will be lost.
+
+  It is good Python design practice not to use mutable class-data, so
+  this property of the ZODB shouldn't cramp your style.
+ 
+We can easily amend this by adding one line to the code:
+
+.. include:: groktut/the_rules_of_persistence2/src/sample/app.py
+  :literal:
+
+We've now told Zope that the context object has changed (because we
+modified a mutable sub-object), by adding the line::
+
+  self.context._p_changed = True
+
+If you now add some texts and then restart Zope, you will notice the
+data is still there: it has successfully been stored in the object
+database.
+
+The code shown so far is a bit ugly in the sense that typically we
+would want to manage our state in the model code (the ``Sample``
+object in this case), and not in the view. Let's make one final
+change to show what that would look like:
+
+.. include:: groktut/the_rules_of_persistence3/src/sample/app.py
+  :literal:
+
+As you can see, we have created a method ``addText`` to the model that
+takes care of amending the list and informing the ZODB about it. This
+way, any view code can safely use the API of ``Sample`` without having
+to worry about the rules of persistence itself, as that is the model's
+responsibility.
+
+Explicitly associating a view with a model
+------------------------------------------
+
+How does Grok know that a view belongs to a model? In the previous
+examples, Grok has made this association automatically. Grok could do
+this because there was only a single model defined in the module
+(``Sample``). In this case, Grok is clever enough to automatically
+associate all views defined elsewhere in the same module to the only
+model. Behind the scenes Grok made the model the *context* of the
+views.
+
+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 in the
+Grok Admin interface. 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.
+
+Containers 
+----------
+
+A container is a special kind of model object that can contain other
+objects. Our ``Sample`` application is already a container, as it
+subclasses ``grok.Container``. What we will do in this section is
+build an application that actually puts something into that container.
+
+Grok applications are typically composed of containers and
+models. Containers are objects that can contain models. This includes
+other containers, as a container is just a special kind of model.
+
+From the perspective of Python, you can think of containers as
+dictionaries.  They allow item access (``container['key']``) to get at
+its contents. They also define methods such as ``keys()`` and
+``values()``. Containers do a lot more than Python dictionaries
+though: they are persistent, and when you modify them, you don't have
+to use `_p_changed` anywhere to notice you changed them. They also
+send out special events that you can listen to when items are placed
+in them or removed from them. For more on that, see the section on
+events (XXX).
+
+Our application object will have a single index page that displays the
+list of items in the container. You can click an item in the list to
+view that item. Below the list, it will display a form that allows you
+to create new items.
+
+Here is the ``app.py`` of our new application:
+
+.. include:: groktut/containers/src/sample/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.
+
+Next are the views. We have an ``index`` page for the ``Sample``
+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.
+
+Here is the associated template for ``SampleIndex``, ``sampleindex.pt``:
+
+.. include:: groktut/containers/src/sample/app_templates/sampleindex.pt
+  :literal:
+
+The first section in the template (``<h2>Existing entries</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
+of the items in the container. We create a link to these items using
+``view.url()``.
+
+The next section (``<h2>Add a new entry</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()``.
+
+Finally, we have an ``index`` page for ``Entry``. It just has a template
+to display the ``text`` attribute:
+
+.. include:: groktut/containers/src/sample/app_templates/entryindex.pt
+  :literal:
+
+Restart Zope and try this application.  Call your application
+``test``. Pay special attention to the URLs.
+
+First, we have the index page of our application:
+
+  http://localhost:8080/test
+
+When we create an entry called ``hello`` in the form, and then click on it
+in the list, you see an URL that looks like this:
+
+  http://localhost:8080/test/hello
+
+We are now looking at the index page of the instance of ``Entry``
+called ``hello``.
+
+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
+instances of ``Entry``, but also other containers. If you made those
+modifications, you would be on your way to building your own content
+management system with Grok.

Deleted: grok/trunk/doc/tutorial.txt
===================================================================
--- grok/trunk/doc/tutorial.txt	2008-05-01 10:16:53 UTC (rev 85969)
+++ grok/trunk/doc/tutorial.txt	2008-05-01 10:22:28 UTC (rev 85970)
@@ -1,1350 +0,0 @@
-=============
-Grok tutorial
-=============
-
-.. raw:: html
-
-   Also available as <a href="./tutorial.pdf">PDF</a>.
-
-.. contents::
-
-Welcome to the Grok tutorial!
-=============================
-
-.. sidebar:: Getting started with Zope Page Templates
-
-  You can find introductions and more information about Zope Page
-  Templates (ZPT, sometimes also called TAL) in various places:
-
-    http://plone.org/documentation/tutorial/zpt
-
-    http://wiki.zope.org/ZPT/FrontPage
-
-  Note that some of the information in these introductions may refer
-  to concepts not available in Grok or Zope 3, in particular variables
-  like ``here`` or ``template``. The basic principles will work with
-  Zope 3 (and Grok) however; try reading ``context`` or ``view``
-  instead.
-
-Grok is a powerful and flexible web application framework for Python
-developers.  In this tutorial we will show you the various things you
-can do with Grok, and how Grok can help you build your web
-application. We'll start out simple, and will slowly go to more
-complex usage patterns.
-
-All you're expected to know is the Python programming language and an
-understanding of basic web programming (HTML, forms, URLs). It also
-helps if you are familiar with Zope Page Templates, though most of the
-examples should be fairly obvious if you are already familiar with
-another templating language.
-
-We recommend that beginners follow the tutorial from top to bottom. The
-tutorial is designed to explain important concepts in order and slowly
-builds up from there.
-
-If you are more experienced, or just curious, you may want to skip
-around instead and read the pieces which interest you most. If
-something is unclear, you can always backtrack to previous sections.
-
-Grok is based on Zope 3 and is compatible with Zope 3, but you do not
-need to know Zope 3 (or Zope 2) at all to follow this tutorial. Grok
-builds on existing Zope 3 technology but exposes it in a different way
-to the developer. We believe Grok makes developing with Zope 3
-technology easier and more fun for beginners and experienced
-developers alike.
-
-Getting started with Grok
-=========================
-
-This chapter will help you get up and running with Grok, using the
-``grokproject`` tool. We create a new project with ``grokproject``,
-tell you how to get that project running so you can access it with a
-web browser.
-
-Setting up grokproject
-----------------------
-
-.. sidebar:: Installing ``easy_install``
-
-  If you don't already have ``easy_install`` available, you can find the
-  script to set it up on the `PEAK EasyInstall page`_.
-
-  .. _`PEAK EasyInstall page`: http://peak.telecommunity.com/DevCenter/EasyInstall#installing-easy-install
-
-  You need to download `ez_setup.py`_. Then, you run it like this to
-  install ``easy_install`` into your system Python::
-
-    $ sudo python2.4 ez_setup.py
-
-  .. _`ez_setup.py`: http://peak.telecommunity.com/dist/ez_setup.py
-
-  This will make ``easy_install`` available to you.
-
-  **Note**: Sometimes you have ``easy_install`` installed but you need
-  a newer version of the underlying setuptools infrastructure to make
-  Grok work. You can automatically upgrade setuptools this by doing::
-
-    $ sudo easy_install -U setuptools
-
-Setting up grok on a Unix-like (Linux, Mac OS X) environment is
-easy. 
-
-Let's go through the prerequisites first. You need a computer
-connected to the internet, as Grok installs itself over the
-network. You also need Python 2.4 installed (Python 2.5 is not
-yet supported, and does not pass all unit tests, though some
-have reported success using it with Grok.)
-
-Because Grok uses a source distribution of Zope 3, you may need to
-install your operating system's Python "dev" package. You also need a
-working C compiler (typically ``gcc``) installed, as we compile bits of
-Zope 3 during setup. Finally, you also need ``easy_install`` installed
-so it becomes easy to install eggs.
-
-Once you are done with the prerequisites, you can install
-grokproject itself::
-
-  $ sudo easy_install grokproject
-
-We're ready to create our first grok project now!
-
-Creating a grok project
------------------------
-
-Let's create a first Grok project. A Grok project is a working
-environment for a developer using Grok. In essence, a directory with a
-lot of files and subdirectories in it. Let's create a Grok project
-called Sample::
-
-  $ grokproject Sample
-
-This tells grokproject to create a new subdirectory called ``Sample``
-and set up the project in there. grokproject will automatically
-download and install Zope 3 and Grok into the project area.
-
-You will be asked a number of questions now. First you need to supply
-the name of the initial module that your package will contain. We'll
-stick with the default ``app.py``::
- 
-  Enter module (Name of a demo Python module placed into the package) ['app.py']:
-
-After this Grok asks you for an initial username and password for the
-Zope server. We'll use ``grok`` for both::
-
-  Enter user (Name of an initial administrator user): grok
-  Enter passwd (Password for the initial administrator user): grok
-  Enter eggs_dir (Location where zc.buildout will look for and place packages) ['/home/<user>/buildout-eggs']:
-
-For the last question, we'll stick with the default path which will be
-a directory called 'buildout-eggs' in your home directory.
-
-Now you have to wait while grokproject downloads `zc.buildout`_
-(the system that's used to build the project area), Grok and the Zope
-3 libraries.
-
-After all that, Grok, along with a Zope 3 instance, is ready to go. 
-
-Starting up Zope
-----------------
-
-You can go into the ``Sample`` project directory now and start up the
-Zope instance that has been installed::
-
-  $ cd Sample
-  $ bin/zopectl fg
-
-This will make Zope 3 available on port 8080, and you can log in with
-username ``grok`` and password ``grok``. Assuming you've started up
-Zope on your localhost, you can go to it here:
-
-  http://localhost:8080
-
-This first pops up a login dialog (username: ``grok`` and password:
-``grok``). It will then show a simple Grok admin interface. This
-allows you to install new Grok applications. 
-
-Our sample application (``sample.app.Sample``) will be available for
-adding. Let's try this out.  Go to the Grok admin page:
-
-  http://localhost:8080
-
-and add a Sample application. Give it the name ``test``.
-
-You can now go to the installed application if you click on its link. This
-will bring you to the following URL:
-
-  http://localhost:8080/test
-
-You should see a simple web page with the following text on it::
-
-  Congratulations!
-
-  Your Grok application is up and running. Edit
-  sample/app_templates/index.pt to change this page.
-
-You can shut down Zope 3 at any time by hitting ``CTRL-c``. Shut it
-down now. We will be shutting down and starting up Zope 3 often in
-this tutorial.
-
-Practice restarting Zope now, as you'll end up doing it a lot during
-this tutorial. It's just stopping Zope and starting it again:
-`CTRL-c`` and then ``bin/zopectl fg`` from your Sample
-project directory.
-
-An empty Grok project
----------------------
-
-.. sidebar:: What about the other directories and files in our project?
-
-  What about the other files and subdirectories in our ``Sample`` project
-  directory? Grokproject sets up the project using a system called
-  `zc.buildout`_. The ``eggs``, ``develop-eggs`` and ``bin``
-  directories are all set up and maintained by zc.buildout. See its
-  documentation for more information about how to use it. The
-  configuration of the project and its dependency is in
-  ``buildout.cfg``. For now, you can avoid these details however.
-
-  .. _`zc.buildout`: http://cheeseshop.python.org/pypi/zc.buildout
-
-Let's take a closer look at what's been created in the Sample project
-directory.
-
-One of the things grokproject created was a ``setup.py`` file. This file
-contains information about your project. This information is used by
-Python distutils and setuptools. You can use the ``setup.py`` file to
-upload your project to the Python Cheeseshop. We will discuss this in
-more detail later in this tutorial. (XXX)
-
-We have already seen the ``bin`` directory. It contains the startup
-script for the Zope instance (``bin/zopectl``) as well as the
-executable for the buildout system (``bin/buildout``) which can be
-used to re-build the Zope instance and possibly update the Grok and
-Zope packages.
-
-The ``parts`` directory contains configuration and data created by
-``buildout``, such as the Zope object database (ZODB) instance.
-
-The actual code of the project will all be inside the ``src``
-directory. In it is a Python package directory called ``sample`` with
-the ``app.py`` file that grokproject said it would create. Let's look
-at this file:
-
-.. include:: groktut/an_empty_grok_project/src/sample/app.py
-   :literal:
-
-Not very much yet, but enough to make an installable Grok application
-and display its welcome page. We'll go into the details of what this
-means later.
-
-Besides this, there is an empty ``__init__.py`` file to make this
-directory a Python package. 
-
-There is also a directory called ``app_templates``. It contains a single
-template called ``index.pt``:
-
-.. include:: groktut/an_empty_grok_project/src/sample/app_templates/index.pt
-  :literal:
-
-This is the template for your project's welcome page.
-
-What's left is a ``configure.zcml`` file. Unlike in typical Zope 3
-applications, this will only ever contain a few lines that load Grok
-and then register this application with Grok. This means we can
-typically completely ignore it, but we'll show it here once for good
-measure:
-
-.. include:: groktut/an_empty_grok_project/src/sample/configure.zcml
-   :literal:
-
-Showing pages
-=============
-
-Showing web pages is what puts the *web* in "web applications". You
-start doing this with HTML templates, but Grok doesn't stop at
-templates. Most web pages in a web application will contain complex
-presentation logic that is better handled by separate Python code in
-conjunction with templates. This becomes especially important in more
-complex interactions with the user, such as form handling. After
-reading this chapter, you should already be able to write simple web
-applications with Grok.
-
-Publishing a simple web page
-----------------------------
-
-Let's publish a simple static web page. Grok is geared towards web
-applications and therefore not really meant for publishing a large
-number of static (pregenerated) web pages. For that you're better off
-to use a specialized system such as Apache. Nonetheless, in order to
-develop any web application we need to know how to put some simple
-HTML on the web.
-
-As you saw previously, our ``Sample`` application has a stock front
-page, generated by grokproject. Let's change that.
-
-To do this, go to the ``app_templates`` directory in ``src/sample/``.
-This directory contains the templates used for anything defined in the
-``app`` module. Grok knows to associate the directory to the module by
-its name (``<module_name>_templates``).
-
-In this directory we will edit the ``index`` template for our
-``Sample`` application object. To do this, open the ``index.pt`` file
-in a text editor. The ``.pt`` extension indicates that this file is a
-Zope Page Template (ZPT). We're just going to put HTML in it now, but
-this allows us to make page dynamic later on.
-
-Change the ``index.pt`` file to contain the following (very
-simplistic) HTML:
-
-.. include:: groktut/publishing_a_simple_web_page/src/sample/app_templates/index.pt
-  :literal:
-
-Then reload the page:
-
-  http://localhost:8080/test
-
-You should now see the following text::
-
-  Hello world!
-
-Note that you can change templates and see the effects instantly:
-there is no need to restart Zope to see the effect. This is not true
-for changes on the Python level, for instance when you add a
-template. We show an example of this next.
-
-A second view
--------------
-
-Our view is named ``index``. This in fact means something slightly
-special: it's the default view of our application object. We can also
-access it explicitly by naming the view:
-
-  http://localhost:8080/test/index
-
-If you view that URL in your browser, you should see the same result
-as before. This is the way all other, non-index views are accessed.
-
-Often, your application needs more than one view. A document for
-instance may have an ``index`` view that displays it, but another
-``edit`` view to change its contents.  To create a second view, create
-another template called ``bye.pt`` in ``app_templates``. Make it have
-the following content:
-
-.. include:: groktut/a_second_view/src/sample/app_templates/bye.pt
-  :literal:
-
-Now we need to tell Grok to actually use this template. To do this,
-modify ``src/sample/app.py`` so that it reads like this:
-
-.. include:: groktut/a_second_view/src/sample/app.py
-  :literal:
-
-As you can see, all we did was add a class called ``Bye`` that
-subclasses from ``grok.View``. This indicates to Grok that we want a
-view named ``bye`` for the application, just like the ``Index`` class
-that was already created for us indicates that we want a view named
-``index``. A *view* is a way to view some model, in this case
-installations of our ``Sample`` application. Note that the view name
-in the URL is always going to be lowercase, while the class name
-normally starts with an uppercase letter.
-
-The empty class definition above is enough for Grok to go look in the
-``app_templates`` directory for ``bye.pt``. The rule is that a the
-template should have the same name as the class, but lowercased and
-with the ``.pt`` postfix.
-
-Restart Zope (``CTRL-C, then ``bin/zopectl fg``). You can now go to a
-new web page called ``bye``:
-
-  http://localhost:8080/test/bye
-
-When you load this web page in a browser, you should see the following
-text::
-
-  Bye world!
-
-Making our page dynamic
------------------------
-
-Static web pages are not very helpful if we want to make a dynamic web
-application. Let's make a page that shows the result of a very simple
-calculation: ``1 + 1``. 
-
-We will use a Zope Page Templates (ZPT) directive to do this
-calculation inside ``index.pt`` template. Change the ``index.pt`` to
-read like this:
-
-.. include:: groktut/making_our_page_dynamic/src/sample/app_templates/index.pt
-  :literal:
-
-We've used the ``tal:content`` page template directive to replace the
-content between the ``<p>`` and ``</p>`` tags with something else, in
-this case the result of the Python expression ``1 + 1``.
-
-Since restarting Zope is not necessary for changes that are limited to
-the page templates, you can just reload the web page:
-
-  http://localhost:8080/test
-
-You should see the following result::
-
-  2
-
-Looking at the source of the web page shows us this::
-
-  <html>
-  <body>
-  <p>2</p>
-  </body>
-  </html>
-
-As you can see, the content of the ``<p>`` tag was indeed replaced
-with the result of the expression ``1 + 1``.
-
-Static resources for our web page
----------------------------------
-
-In real-world web pages, we almost never publish a web page that just
-contains bare-bones HTML. We also want to refer to other resources,
-such as images, CSS files or Javascript files. As an example, let's
-add some style to our web page.
-
-To do this, create a new directory called ``static`` in the ``sample``
-package (so, ``src/sample/static``). In it, place a file called
-``style.css`` and put in the following content:
-
-.. include:: groktut/static_resources_for_our_web_page/src/sample/static/style.css
-  :literal:
-
-In order to use it, we also need to refer to it from our
-``index.pt``. Change the content of ``index.pt`` to read like this:
-
-.. include:: groktut/static_resources_for_our_web_page/src/sample/app_templates/index.pt
-  :literal:
-
-Now restart Zope and reload the page:
-
-  http://localhost:8080/test
-
-The web page should now show up with a red background.
-
-You will have noticed we used the ``tal:attributes`` directive in our
-``index.pt`` now. This uses Zope Page Templates to dynamically
-generate the link to our file ``style.css``.
-
-Let's take a look at the source code of the generated web page::
-
-  <html>
-  <link rel="stylesheet" type="text/css"
-        href="http://localhost:8080/test/@@/sample/style.css" />
-  <body>
-  <p>Hello world!</p>
-  </body>
-  </html>
-
-As you can see, the ``tal:attributes`` directive is gone and has been
-replaced with the following URL to the actual stylesheet:
-
-  http://localhost:8080/test/@@/sample/style.css
-
-We will not go into the details of the structure of the URL here, but
-we will note that because it's generated this way, the link to
-``style.css`` will continue to work no matter where you install your
-application (i.e. in a virtual hosting setup).
-
-Pulling in images or javascript is very similar. Just place your image
-files and `.js` files in the ``static`` directory, and create the URL
-to them using ``static/<filename>`` in your page template.
-
-Using view methods
-------------------
-
-.. sidebar:: Unassociated templates
-
-  If you have followed the tutorial so far, you will have an extra
-  template called ``bye.pt`` in your ``app_templates`` directory.
-  Since in the given ``app.py``e we have no more class using it, the
-  ``bye.pt`` template will have become *unassociated**. When you try
-  to restart Zope, grok will be unable to read your application, and
-  Zope will crash with an error message like this::
-
-    GrokError: Found the following unassociated template(s) when
-    grokking 'sample.app': bye.  Define view classes inheriting from
-    grok.View to enable the template(s).
-
-  To resolve this error, simply remove ``bye.pt`` from your
-  ``app_templates`` directory.
-
-ZPT is deliberately limited in what it allows you to do with Python.
-It is good application design practice to use ZPT for fairly simple
-templating purposes only, and to do anything a bit more complicated in
-Python code. Using ZPT with arbitrary Python code is easy: you just
-add methods to your view class and use them from your template.
-
-Let's see how this is done by making a web page that displays the
-current date and time. We will use our Python interpreter to find out
-what works::
-
-  $ python
-  Python 2.4.4
-  Type "help", "copyright", "credits" or "license" for more information.
-  >>> 
-
-We will need Python's ``datetime`` class, so let's import it::
-
-  >>> from datetime import datetime
-
-Note that this statement brings us beyond the capabilities of simple
-ZPT use; it is not allowed to import arbitrary Python modules from
-within a ZPT template; only Python *expressions* (with a result) are
-allowed, not *statements* such as ``from .. import ..``.
-
-Let's get the current date and time::
-
-  >>> now = datetime.now()
-
-This gives us a date time object; something like this::
-
-  >>> now
-  datetime.datetime(2007, 2, 27, 17, 14, 40, 958809)
-
-Not very nice to display on a web page, so let's turn it into a
-prettier string using the formatting capabilities of the ``datetime``
-object::
-
-  >>> now.strftime('%Y-%m-%d %H:%M')
-  '2007-02-27 17:14'
-
-That looks better.
-
-So far nothing new; just Python. We will integrate this code into our
-Grok project now. Go to ``app.py`` and change it to read like this:
-
-.. include:: groktut/using_view_methods/src/sample/app.py
-  :literal:
-
-We've simply added a method to our view that returns a string
-representing the current date and time. Now to get this string in our
-page template. Change ``index.pt`` to read like this:
-
-.. include:: groktut/using_view_methods/src/sample/app_templates/index.pt
-  :literal:
-
-Restart Zope. This is needed as we changed the content of a Python
-file (``app.py``). Now reload our index page to see whether it worked:
-
-  http://localhost:8080/test
-
-You should see a web page with a date and time like this on your
-screen now::
-
-  2007-02-27 17:21
-
-What happened here? When viewing a page, the view class (in this case
-``Index`` is instantiated by Zope. The name ``view`` in the template
-is always made available and is associated with this instance. We then
-simply call the method on it in our template.
-
-There is another way to write the template that is slightly shorter
-and may be easier to read in some cases, using a ZPT path expression::
-
-  <html>
-  <body>
-  <p tal:content="view/current_datetime"></p>
-  </body>
-  </html>
-
-Running this has the same result as before.
-
-Generating HTML from Python
----------------------------
-
-While usually you will be using templates to generate HTML, sometimes
-you want to generate complicated HTML in Python and then include it in
-an existing web page. For reasons of security against cross-site
-scripting attacks, TAL will automatically escape any HTML into `&gt;`
-and `&lt;`. With the ``structure`` directive, you can tell TAL
-explicitly to not escape HTML this way, so it is passed literally into
-the template. Let's see how this is done. Change ``app.pt`` to read like
-this:
-
-.. include:: groktut/generating_html_from_python/src/sample/app.py
-  :literal:
-
-and then change ``index.pt`` to read like the following:
-
-.. include:: groktut/generating_html_from_python/src/sample/app_templates/index.pt
-  :literal:
-
-Let's take another look at our web page:
-
-  http://localhost:8080/test
-
-You should see the following text (in bold):
-
-  **ME GROK BOLD**
-
-This means the HTML we generated from the ``some_html`` method was
-indeed successfully integrated in our web page.  Without the the
-``structure`` directive, you would've seen the following instead::
- 
-  <b>ME GROK BOLD</b>
-
-Completely Python-driven views
-------------------------------
-
-.. sidebar:: Setting the content-type
-
-  When generating the complete content of a page yourself, it's often
-  useful to change the content-type of the page to something else than
-  ``text/plain``. Let's change our code to return simple XML and set
-  the content type to ``text/xml``:
-
-  .. include:: groktut/setting_the_content_type/src/sample/app.py
-    :literal:
-
-  All views in Grok have a ``response`` property that you can use to
-  manipulate response headers.
-
-Sometimes it is inconvenient to have to use a template at all. Perhaps
-we are not returning a HTML page at all, for instance. In this case,
-we can use the special ``render`` method on a view.
-
-Modify ``app.py`` so it reads like this:
-
-.. include:: groktut/completely_python_driven_views/src/sample/app.py
-  :literal:
-
-If you were to start up Zope with an ``index.pt`` template still
-inside ``app_templates`` you would get an error::
-
-    GrokError: Multiple possible ways to render view <class
-    'sample.app.Index'>. It has both a 'render' method as well as an
-    associated template.
-
-In the face of ambiguity Grok, like Python, refuses to guess. To
-resolve this error, remove ``index.pt`` from the ``app_templates``
-directory.
-
-Now take another look at our test application:
-
-  http://localhost:8080/test
-
-You should see the following::
-
-  ME GROK NO TEMPLATE
-
-You should see this even when you view the source of the page. When
-looking at the content type of this page, you will see that it is
-``text/plain``.
-
-Doing some calculation before viewing a page
---------------------------------------------
-
-Instead of calculating some values in a method call from the template,
-it is often more useful to calculate just before the web page's
-template is calculated. This way you are sure that a value is only
-calculated once per view, even if you use it multiple times.
-
-You can do this by defining an ``update`` method on the view class. Modify
-``app.py`` to read like this:
-
-.. include:: groktut/doing_some_calculation_before_viewing_a_page/src/sample/app.py
-  :literal:
-
-This sets a name ``alpha`` on the view just before the template is
-being displayed, so we can use it from the template. You can set as
-many names on ``self`` as you like.
-
-Now we need a template ``index.pt`` that uses ``alpha``:
-
-.. include:: groktut/doing_some_calculation_before_viewing_a_page/src/sample/app_templates/index.pt
-  :literal:
-
-Restart Zope and then let's take another look at our application:
-
-  http://localhost:8080/test
-
-You should see 256, which is indeed 2 raised to the power 8.
-
-Reading URL parameters
-----------------------
-
-When developing a web application, you don't just want to output data,
-but also want to use input. One of the simplest ways for a web
-application to receive input is by retrieving information as a URL
-parameter. Let's devise a web application that can do sums for us. In
-this application, if you enter the following URL into that
-application:
-
-  http://localhost:8080/test?value1=3&value2=5
-
-you should see the sum (8) as the result on the page. 
-
-Modify ``app.py`` to read like this:
-
-.. include:: groktut/reading_url_parameters/src/sample/app.py
-  :literal:
-
-We need an ``index.pt`` that uses ``sum``:
-
-.. include:: groktut/reading_url_parameters/src/sample/app_templates/index.pt
-  :literal:
-
-Restart Zope. Now going to the folllowing URL should display 8:
-
-  http://localhost:8080/test?value1=3&value2=5
-
-Other sums work too, of course:
-
-  http://localhost:8080/test?value1=50&value2=50
-
-What if we don't supply the needed parameters (``value1`` and
-``value2``) to the request? We get an error:
-
-  http://localhost:8080/test
-
-You can look at the window where you started up Zope to see the error
-traceback. This is the relevant complaint::
-
-  TypeError: Missing argument to update(): value1
-
-We can modify our code so it works even without input for either parameter:
-
-.. include:: groktut/reading_url_parameters2/src/sample/app.py
-  :literal:
-
-Restart Zope, and see it can now deal with missing parameters (they
-default to ``0``).
-
-Simple forms
-------------
-
-.. sidebar:: Automatic forms
-
-  Creating forms and converting and validating user input by hand, as
-  shown in this section, can be rather cumbersome. With Grok, you can
-  use Zope 3's *schema* and *formlib* systems to automate this and
-  more. This will be discussed in a later section. XXX
-
-Entering the parameters through URLs is not very pretty. Let's use a
-form for this instead. Change ``index.pt`` to contain a form, like
-this:
-
-.. include:: groktut/simple_forms/src/sample/app_templates/index.pt
-  :literal:
-
-One thing to note here is that we dynamically generate the form's
-``action``. We make the form submit to itself, basically. Grok views
-have a special method called ``url`` that you can use to retrieve the
-URL of the view itself (and other URLs which we'll go into later).
-
-Leave the ``app.py`` as in the previous section, for now. You can now
-go to the web page::
-
-  http://localhost:8080/test
-
-You can submit the form with some values, and see the result displayed
-below.
-
-We still have a few bugs to deal with however. For one, if we don't fill
-in any parameters and submit the form, we get an error like this::
-
-  File "../app.py", line 8, in update
-    self.sum = int(value1) + int(value2)
-  ValueError: invalid literal for int(): 
-
-This is because the parameters were empty strings, which cannot be
-converted to integers. Another thing that is not really pretty is that
-it displays a sum (0) even if we did not enter any data. Let's change
-``app.py`` to take both cases into account:
-
-.. include:: groktut/simple_forms2/src/sample/app.py
-  :literal:
-
-We catch any TypeError and ValueError here so that wrong or missing
-data does not result in a failure. Instead we display the text "No
-sum". If we don't get any error, the conversion to integer was fine,
-and we can display the sum.
-
-Restart Zope and go to the form again to try it out:
-
-  http://localhost:8080/test
-
-Models
-======
-
-Now we know how to show web pages, we need to go into what we are
-actually showing: the models. The models contain the
-display-independent logic of your application. In this chapter we will
-discuss a number of issues surrounding models: how your views connect
-to models, and how you can make sure the data in your models is stored
-safely. As the complexity of our sample applications grows, we will
-also go into a few more issues surrounding form handling.
-
-A view for a model
-------------------
-
-So far, we have only seen views that do the work all by themselves.
-In typical applications this is not the case however - views display
-information that is stored elsewhere. In Grok applications, views work
-for models: subclasses of ``grok.Model`` or ``grok.Container``. For
-the purposes of this discussion, we can treat a ``grok.Container`` as
-another kind of ``grok.Model`` (more about what makes
-``grok.Container`` special later XXX).
-
-Our ``Sample`` class is a ``grok.Container``, so let's use ``Sample``
-to demonstrate the basic principle. Let's modify ``app.py`` so that
-``Sample`` actually makes some data available:
-
-.. include:: groktut/a_view_for_a_model/src/sample/app.py
-  :literal:
-
-In this case, the information (``"This is important information!"``)
-is just hardcoded, but you can imagine information is retrieved from
-somewhere else, such as a relational database or the filesystem.
-
-We now want to display this information in our template ``index.pt``:
-
-.. include:: groktut/a_view_for_a_model/src/sample/app_templates/index.pt
-  :literal:
-
-Restart Zope. When you view the page:
-
-  http://localhost:8080/test
-
-You should now see the following::
-
-  This is important information!
-
-Previously we have seen that you can access methods and attributes on
-the view using the special ``view`` name in a template. Similarly, the
-name ``context`` is also available in each template. ``context``
-allows us to access information on the context object the view is
-displaying. In this case this is an instance of ``Sample``, our
-application object.
-
-Separating the model from the view that displays it is an important
-concept in structuring applications. The view, along with the
-template, is responsible for displaying the information and its user
-interface. The model represents the actual information (or content)
-the application is about, such as documents, blog entries or wiki
-pages. The model should not know anything about the way it is
-displayed.
-
-This way of structuring your applications allows you to change the way
-your model is displayed without modifying the model itself, just
-the way it is viewed.
-
-Let's do that by making the view do something to the information. Change 
-``app.py`` again:
-
-.. include:: groktut/a_view_for_a_model2/src/sample/app.py
-  :literal:
-
-You can see that it is possible to access the context object (an
-instance of ``Sample``) from within the view class, by accessing the
-``context`` attribute. This gets the same object as when we used the
-``context`` name in our template before.
-
-What we do here is reverse the string returned from the
-``information()`` method. You can try it on the Python prompt::
-
-  >>> ''.join(reversed('foo'))
-  'oof'
-
-Now let's modify the ``index.pt`` template so that it uses the
-``reversed_information`` method:
-
-.. include:: groktut/a_view_for_a_model2/src/sample/app_templates/index.pt
-  :literal:
-
-Restart Zope. When you view the page:
-
-  http://localhost:8080/test
-
-You should now see the following:
-
-  The information: This is important information!
-
-  The information, reversed: !noitamrofni tnatropmi si sihT 
-
-Storing data
-------------
-
-So far we have only displayed either hardcoded data, or calculations
-based on end-user input. What if we actually want to *store* some
-information, such as something the user entered? The easiest way to do
-this with Zope is to use the Zope Object Database (ZODB).
-
-The ZODB is a database of Python objects. You can store any Python
-object in it, though you do need to follow a few simple rules (the
-"rules of persistence", which we will go into later). Our ``Sample``
-application object is stored in the object database, so we can store
-some information on it.
-
-Let's create an application that stores a bit of text for us. We will
-use one view to view the text (``index``) and another to edit it
-(``edit``).
-
-Modify ``app.py`` to read like this:
-
-.. include:: groktut/storing_data/src/sample/app.py
-  :literal:
-
-The ``Sample`` class gained a class attribute with some default text.
-In the ``update`` method of the ``Edit`` view you can see we actually
-set the ``text`` attribute on the context, if at least a ``text``
-value was supplied by a form. This will set the ``text`` attribute on
-the instance of the ``Sample`` object in the object database, and thus
-will override the default ``text`` class attribute.
-
-Change the ``index.pt`` template to read like this:
-
-.. include:: groktut/storing_data/src/sample/app_templates/index.pt
-  :literal:
-
-This is a very simple template that just displays the ``text``
-attribute of the ``context`` object (our ``Sample`` instance).
-
-Create an ``edit.pt`` template with the following content:
-
-.. include:: groktut/storing_data/src/sample/app_templates/edit.pt
-  :literal:
-
-This template display a form asking for a bit of text. It submits to
-itself.
-
-Restart Zope. Let's first view the index page:
-
-  http://localhost:8080/test
-
-You should see ``default text``.
-
-Now let's modify the text by doing to the edit page of the application:
-
-  http://localhost:8080/test/edit
-
-Type in some text and press the "Store" button. Since it submits to
-itself, we will see the form again, so go to the index page manually:
-
-  http://localhost:8080/test
- 
-You should now see the text you just entered on the page. This means
-that your text was successfully stored in the object database!
-
-You can even restart Zope and go back to the index page, and your text
-should still be there.
-
-Redirection
------------
-
-Let's make our application a bit easier to use. First, let's change
-``index.pt`` so it includes a link to the edit page. To do this, we
-will use the ``url`` method on the view:
-
-.. include:: groktut/redirection/src/sample/app_templates/index.pt
-  :literal:
-
-Giving ``url`` a single string argument will generate a URL to the
-view named that way on the same object (``test``), so in this case
-``test/edit``.
-
-Now let's change the edit form so that it redirects back to the
-``index`` page after you press the submit button:
-
-.. include:: groktut/redirection/src/sample/app.py
-  :literal:
-
-The last line is the new one. We use the ``url`` method on the view to
-construct a URL to the ``index`` page. Since we're in the template, we
-can simply call ``url`` on ``self``. Then, we pass this to another
-special method available on all ``grok.View`` subclasses,
-``redirect``. We tell the system to redirect to the ``index`` page.
-
-Showing the value in the form
------------------------------
-
-Let's change our application so it displays what we stored the edit
-form as well, not just on the index page.
-
-To make this work, change edit.pt so it reads like this:
-
-.. include:: groktut/showing_the_value_in_the_form/src/sample/app_templates/edit.pt
-  :literal:
-
-The only change is that we have used ``tal:attributes`` to include the
-value of the ``text`` attribute of the context object in the form.
-
-The rules of persistence
-------------------------
-
-These are the "rules of persistence":
-
-* You should subclass classes that want to store data from
-  ``persistent.Persistent`` so that it's easy to store them in the
-  ZODB. The simplest way to do this with Grok is to subclass from
-  ``grok.Model`` or ``grok.Container``.
-
-* Instances that you want to store should be connected to other
-  persistent classes that are already stored. The simplest way to do
-  this with Grok is to attach them somehow to the ``grok.Application``
-  object, directly or indirectly. This can be done by setting them as
-  an attribute, or by putting them in a container (if you made your
-  application subclass ``grok.Container``).
-
-* To make sure that the ZODB knows you changed a mutable attribute
-  (such as a simple Python list or dictionary) in your instance, set
-  the special ``_p_changed`` attribute on that instance to
-  ``True``. This is only necessary if that attribute is not
-  ``Persistent`` itself. It is also not necessary when you create or
-  overwrite an attribute directly using ``=``.
-
-If you construct your application's content out of ``grok.Model`` and
-``grok.Container`` subclasses you mostly follow the rules
-already. Just remember to set ``_p_changed`` in your methods if you
-find yourself modifying a Python list (with ``append``, for instance)
-or dictionary (by storing a value in it).
-
-The code in the section `Storing data`_ is a simple example. We in
-fact have to do nothing special at all to obey the rules of
-persistence in that case.
-
-If we use a mutable object such as a list or dictionary to store data
-instead, we do need to take special action. Let's change our example
-code (based on the last section) to use a mutable object (a list):
-
-.. include:: groktut/the_rules_of_persistence/src/sample/app.py
-  :literal:
-
-We have now changed the ``Sample`` class to do something new: it has
-an ``__init__`` method. Whenever you create the ``Sample`` application
-object now, it will be created with an attribute called ``list``,
-which will contain an empty Python list. 
-
-We also make sure that the ``__init__`` method of the superclass still
-gets executed, by using the regular Python ``super`` idiom. If we
-didn't do that, our container would not be fully initialized.
-
-You will also notice a small change to the ``update`` method of the
-``Edit`` class. Instead of just storing the text as an attribute of
-our ``Sample`` model, we add each text we enter to the new
-``list`` attribute on. 
-
-Note that this code has a subtle bug in it, which is why we've added
-the comment. We will see what bug this is in a little bit. First,
-though, let's change our templates.
-
-We change ``index.pt`` so that it displays the list:
-
-.. include:: groktut/the_rules_of_persistence/src/sample/app_templates/index.pt
-  :literal:
-
-We've also changed the text of the link to the ``edit`` page to reflect
-the new adding behavior of our application.
-
-We need to undo the change to the ``edit.pt`` template that we
-made in the last section, as each time we edit a text we now *add* a
-new text, instead of changing the original. There is therefore no text
-to show in as the input value anymore:
-
-.. include:: groktut/the_rules_of_persistence/src/sample/app_templates/edit.pt
-  :literal:
-
-.. sidebar:: evolution
-
-  What to do when you change an object's storage structure while your
-  application is already in production? In a later section, we will
-  introduce Zope 3's object evolution mechanism that allows you to
-  update objects in an existing object database. XXX
-
-Let's restart our Zope application. If you have followed the tutorial
-from the last section, you will now see an error when you look at the
-front page of the application::
-
-  A system error occurred. 
-
-Look at the output Zope gave when we tried to load our page::
-
-  AttributeError: 'Sample' object has no attribute 'list'
-
-But we just changed our object to have an attribute ``list``, right?
-Yes we did, but only for *new* instances of the Sample object. What we
-are looking at is the sample object from before, still stored in the
-object database. It has no such attribute. This isn't a bug by the way
-(for our actual bug, see later in this section): it is just a database
-problem.
-
-What to do now? The simplest action to take during development is to
-simply remove our previously installed application, and create a new
-one that *does* have this attribute. Go to the Grok admin screen:
-
-  http://localhost:8080
-
-Select the application object (``test``) and delete it. Now install it
-again, as ``test``. Now go to its edit screen and add a text:
-
-  http://localhost:8080/test/edit
-
-Click on ``add a text`` and add another text. You will see the new
-texts appear on the ``index`` page.
-
-Everything is just fine now, right? In fact, not so! Now we will get
-to our bug. Restart Zope and look at the index page again:
-
-  http://localhost:8080/test
-
-None of the texts we added were saved! What happened? We broke the
-third rule of persistence as described above: we modified a mutable
-attribute and did not notify the database that we made this
-change. This means that the object database was not aware of our
-change to the object in memory, and thus never saved it to disk.
-
-.. sidebar: The ZODB only stores instance data
-
-  Note that the ZODB only stores ("persists") instance data. This
-  means that any data you have directly associated with a class, as
-  opposed to the instance, won't be persisted. Normally you only
-  associate immutable data with the class, so this is not a problem::
- 
-    class Foo(object):
-        mydata = 'some text'
-
-  That data will be there when the module is imported, and since it 
-  will never be changed, there isn't a problem. Now let's check what
-  happens with mutable data::
-
-    class Foo(object):
-        mydata = []
-
-  Appending an item to mydata (through ``self.mydata.append('bar')``,
-  for instance) have an effect, but only until you restart Zope. Then
-  your changes will be lost.
-
-  It is good Python design practice not to use mutable class-data, so
-  this property of the ZODB shouldn't cramp your style.
- 
-We can easily amend this by adding one line to the code:
-
-.. include:: groktut/the_rules_of_persistence2/src/sample/app.py
-  :literal:
-
-We've now told Zope that the context object has changed (because we
-modified a mutable sub-object), by adding the line::
-
-  self.context._p_changed = True
-
-If you now add some texts and then restart Zope, you will notice the
-data is still there: it has successfully been stored in the object
-database.
-
-The code shown so far is a bit ugly in the sense that typically we
-would want to manage our state in the model code (the ``Sample``
-object in this case), and not in the view. Let's make one final
-change to show what that would look like:
-
-.. include:: groktut/the_rules_of_persistence3/src/sample/app.py
-  :literal:
-
-As you can see, we have created a method ``addText`` to the model that
-takes care of amending the list and informing the ZODB about it. This
-way, any view code can safely use the API of ``Sample`` without having
-to worry about the rules of persistence itself, as that is the model's
-responsibility.
-
-Explicitly associating a view with a model
-------------------------------------------
-
-How does Grok know that a view belongs to a model? In the previous
-examples, Grok has made this association automatically. Grok could do
-this because there was only a single model defined in the module
-(``Sample``). In this case, Grok is clever enough to automatically
-associate all views defined elsewhere in the same module to the only
-model. Behind the scenes Grok made the model the *context* of the
-views.
-
-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 in the
-Grok Admin interface. 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.
-
-Containers 
-----------
-
-A container is a special kind of model object that can contain other
-objects. Our ``Sample`` application is already a container, as it
-subclasses ``grok.Container``. What we will do in this section is
-build an application that actually puts something into that container.
-
-Grok applications are typically composed of containers and
-models. Containers are objects that can contain models. This includes
-other containers, as a container is just a special kind of model.
-
-From the perspective of Python, you can think of containers as
-dictionaries.  They allow item access (``container['key']``) to get at
-its contents. They also define methods such as ``keys()`` and
-``values()``. Containers do a lot more than Python dictionaries
-though: they are persistent, and when you modify them, you don't have
-to use `_p_changed` anywhere to notice you changed them. They also
-send out special events that you can listen to when items are placed
-in them or removed from them. For more on that, see the section on
-events (XXX).
-
-Our application object will have a single index page that displays the
-list of items in the container. You can click an item in the list to
-view that item. Below the list, it will display a form that allows you
-to create new items.
-
-Here is the ``app.py`` of our new application:
-
-.. include:: groktut/containers/src/sample/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.
-
-Next are the views. We have an ``index`` page for the ``Sample``
-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.
-
-Here is the associated template for ``SampleIndex``, ``sampleindex.pt``:
-
-.. include:: groktut/containers/src/sample/app_templates/sampleindex.pt
-  :literal:
-
-The first section in the template (``<h2>Existing entries</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
-of the items in the container. We create a link to these items using
-``view.url()``.
-
-The next section (``<h2>Add a new entry</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()``.
-
-Finally, we have an ``index`` page for ``Entry``. It just has a template
-to display the ``text`` attribute:
-
-.. include:: groktut/containers/src/sample/app_templates/entryindex.pt
-  :literal:
-
-Restart Zope and try this application.  Call your application
-``test``. Pay special attention to the URLs.
-
-First, we have the index page of our application:
-
-  http://localhost:8080/test
-
-When we create an entry called ``hello`` in the form, and then click on it
-in the list, you see an URL that looks like this:
-
-  http://localhost:8080/test/hello
-
-We are now looking at the index page of the instance of ``Entry``
-called ``hello``.
-
-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
-instances of ``Entry``, but also other containers. If you made those
-modifications, you would be on your way to building your own content
-management system with Grok.



More information about the Checkins mailing list