summaryrefslogtreecommitdiff
path: root/docs/tutorials/bfgwiki2/definingmodels.rst
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-05-31 22:47:14 +0000
committerChris McDonough <chrism@agendaless.com>2009-05-31 22:47:14 +0000
commitb2e9bfae66a30b292bd76a287d16505a9b3ecce0 (patch)
tree7e91ae9d02e71d6860b6220d748da7053d6cd5d8 /docs/tutorials/bfgwiki2/definingmodels.rst
parentf6067e641be451819af94db2ee085292372a7cb2 (diff)
downloadpyramid-b2e9bfae66a30b292bd76a287d16505a9b3ecce0.tar.gz
pyramid-b2e9bfae66a30b292bd76a287d16505a9b3ecce0.tar.bz2
pyramid-b2e9bfae66a30b292bd76a287d16505a9b3ecce0.zip
Make a copy of the tutorial for Routes+SQLAlchemy.
Diffstat (limited to 'docs/tutorials/bfgwiki2/definingmodels.rst')
-rw-r--r--docs/tutorials/bfgwiki2/definingmodels.rst147
1 files changed, 147 insertions, 0 deletions
diff --git a/docs/tutorials/bfgwiki2/definingmodels.rst b/docs/tutorials/bfgwiki2/definingmodels.rst
new file mode 100644
index 000000000..61eb5f112
--- /dev/null
+++ b/docs/tutorials/bfgwiki2/definingmodels.rst
@@ -0,0 +1,147 @@
+===============
+Defining Models
+===============
+
+The first change we'll make to our bone-stock paster-generated
+application will be to define a number of :term:`model` constructors.
+For this application, which will be a Wiki, we will need two kinds of
+model constructors: a "Wiki" model constructor, and a "Page" model
+constructor. Both our Page and Wiki constructors will be class
+objects. A single instance of the "Wiki" class will serve as a
+container for "Page" objects, which will be instances of the "Page"
+class.
+
+Adding Model Classes
+--------------------
+
+The first thing we want to do is remove the ``MyModel`` class from the
+generated ``models.py`` file. The ``MyModel`` class is only a sample
+and we're not going to use it.
+
+.. note::
+
+ There is nothing automagically special about the filename
+ ``models.py``. A project may have many models throughout its
+ codebase in arbitrarily-named files. Files implementing models
+ often have ``model`` in their filenames (or they may live in a
+ Python subpackage of your application package named ``models``) ,
+ but this is only by convention.
+
+Then, we'll add a ``Wiki`` class. Because this is a ZODB application,
+this class should inherit from
+``persistent.mapping.PersistentMapping``. We want it to inherit from
+the ``PersistentMapping`` class because our Wiki class will be a
+mapping of wiki page names to ``Page`` objects. The
+``PersistentMapping`` class provides our class with mapping behavior,
+and makes sure that our Wiki page is stored as a "first-class"
+persistent object in our ZODB database.
+
+Our ``Wiki`` class should also have a ``__name__`` attribute set to
+``None`` at class scope, and should have a ``__parent__`` attribute
+set to None at class scope as well. If a model has a ``__parent__``
+attribute of ``None`` in a traversal-based :mod:`repoze.bfg`
+application, it means that it's the :term:`root` model. The
+``__name__`` of the root model is always ``None``.
+
+Then we'll add a ``Page`` class. This class should inherit from
+``persistent.Persistent``. We'll also give it an ``__init__`` method
+that accepts a single parameter named ``data``. This parameter will
+contain the :term:`ReStructuredText` body representing the wiki page
+content. Note that ``Page`` objects don't have an initial
+``__name__`` or ``__parent__`` attribute. All objects in a traversal
+graph must have a ``__name__`` and a ``__parent__`` attribute. We
+don't specify these here because both ``__name__`` and ``__parent__``
+will be set by by a :term:`view` function when a Page is added to our
+Wiki mapping.
+
+Add an Appmaker
+---------------
+
+We're using a mini-framework callable named
+``repoze.zodbconn.finder.PersistentApplicationFinder`` in our
+application (see "run.py"). A ``PersistentApplicationFinder`` accepts
+a ZODB URL as well as an "appmaker" callback. This callback typically
+lives in the ``models.py`` file.
+
+We want to change the appmaker function in our ``models.py`` file so
+that our application root is a Wiki instance, and we'll also slot a
+single page object (the front page) into the wiki.
+
+Looking at the Result of Our Edits to ``models.py``
+---------------------------------------------------
+
+The result of all of our edits to ``models.py`` will end up looking
+something like this:
+
+.. literalinclude:: src/models/tutorial/models.py
+ :linenos:
+ :language: python
+
+Testing the Models
+------------------
+
+To make sure the code we just wrote works, we write tests for the
+model classes and the appmaker. Changing ``tests.py``, we'll write a
+separate test class for each model class, and we'll write a test class
+for the ``appmaker``.
+
+To do so, we'll retain the ``tutorial.tests.ViewTests`` class provided
+as a result of the ``bfg_zodb`` project generator but we'll disuse the
+``ViewIntegrationTests`` class. The ``ViewIntegrationTests`` class is
+too "heavy-hammer" for our tastes. We'll add three test classes: one
+for the ``Page`` model named ``PageModelTests``, one for the ``Wiki``
+model named ``WikiModelTests``, and one for the appmaker named
+``AppmakerTests``.
+
+When we're done changing ``tests.py``, it will look something like so:
+
+.. literalinclude:: src/models/tutorial/tests.py
+ :linenos:
+ :language: python
+
+Running the Tests
+-----------------
+
+We can run these tests by using ``setup.py test`` in the same way we
+did in :ref:`running_tests`. Assuming our shell's current working
+directory is the "tutorial" distribution directory:
+
+On UNIX:
+
+.. code-block:: bash
+
+ $ ../bin/python setup.py test -q
+
+On Windows:
+
+.. code-block:: bash
+
+ c:\bigfntut\tutorial> ..\Scripts\python setup.py test -q
+
+The expected output is something like this:
+
+.. code-block:: bash
+
+ .....
+ ----------------------------------------------------------------------
+ Ran 5 tests in 0.008s
+
+ OK
+
+Declaring Dependencies in Our ``setup.py`` File
+-----------------------------------------------
+
+Our application depends on packages which are not dependencies of the
+original "tutorial" application as it was generated by the ``paster
+create`` command. We'll add these dependencies to our ``tutorial``
+package's ``setup.py`` file by assigning these dependencies to both
+the ``install_requires`` and the ``tests_require`` parameters to the
+``setup`` function. In particular, we require the ``docutils``
+package.
+
+Our resulting ``setup.py`` should look like so:
+
+.. literalinclude:: src/models/setup.py
+ :linenos:
+ :language: python
+