diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-05-31 22:47:14 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-05-31 22:47:14 +0000 |
| commit | b2e9bfae66a30b292bd76a287d16505a9b3ecce0 (patch) | |
| tree | 7e91ae9d02e71d6860b6220d748da7053d6cd5d8 /docs/tutorials/bfgwiki2/definingmodels.rst | |
| parent | f6067e641be451819af94db2ee085292372a7cb2 (diff) | |
| download | pyramid-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.rst | 147 |
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 + |
