diff options
| author | Chris McDonough <chrism@plope.com> | 2010-12-18 02:27:14 -0500 |
|---|---|---|
| committer | Chris McDonough <chrism@plope.com> | 2010-12-18 02:27:14 -0500 |
| commit | fb6a5ce52a275f7798e82a34b5907ea118cbd2ff (patch) | |
| tree | 29e80d0eb681676d1e0eb2707ca764dbf5491864 /docs/narr/models.rst | |
| parent | bf89764a7e3ccab6133c9ad43b8d9af4f5c4083b (diff) | |
| download | pyramid-fb6a5ce52a275f7798e82a34b5907ea118cbd2ff.tar.gz pyramid-fb6a5ce52a275f7798e82a34b5907ea118cbd2ff.tar.bz2 pyramid-fb6a5ce52a275f7798e82a34b5907ea118cbd2ff.zip | |
model -> resource; resource -> asset
Diffstat (limited to 'docs/narr/models.rst')
| -rw-r--r-- | docs/narr/models.rst | 331 |
1 files changed, 0 insertions, 331 deletions
diff --git a/docs/narr/models.rst b/docs/narr/models.rst deleted file mode 100644 index 91828287f..000000000 --- a/docs/narr/models.rst +++ /dev/null @@ -1,331 +0,0 @@ -Models -====== - -A :term:`model` class is typically a simple Python class defined in a module. -References to these classes and instances of such classes are omnipresent in -:app:`Pyramid` when :term:`traversal` is used to build an application: - -- Model instances make up the object graph that :app:`Pyramid` - will walk over when :term:`traversal` is used. - -- The ``context`` and ``containment`` arguments to - :meth:`pyramid.config.Configurator.add_view` often - reference a model class. - -- A :term:`root factory` returns a model instance. - -- A model instance is exposed to :term:`view` code as the :term:`context` of - a view. - -In many :term:`traversal` based applications (particularly ones that use -Zope-like patterns), model objects often store data and offer methods related -to mutating that data. - -.. note:: - - A terminology overlap confuses people who write applications that - always use ORM packages such as SQLAlchemy, which has a very - different notion of the definition of a "model". When using the API - of common ORM packages, its conception of "model" is almost - certainly not the same conception of "model" used by - :app:`Pyramid`. In particular, it can be unnatural to think of - :app:`Pyramid` model objects as "models" if you develop your - application using :term:`traversal` and a relational database. When - you develop such applications, the object graph *might* be composed - completely of "model" objects (as defined by the ORM) but it also - might not be. The things that :app:`Pyramid` refers to as - "models" in such an application may instead just be stand-ins that - perform a query and generate some wrapper *for* an ORM "model" or - set of ORM models. This naming overlap is slightly unfortunate. - However, many :app:`Pyramid` applications (especially ones which - use :term:`ZODB`) do indeed traverse a graph full of literal model - nodes. Each node in the graph is a separate persistent object that - is stored within a database. This was the use case considered when - coming up with the "model" terminology. However, if we had it to do - all over again, we'd probably call these objects something - different to avoid confusion. - -.. index:: - single: model constructor - -Defining a Model Constructor ----------------------------- - -An example of a model constructor, ``BlogEntry`` is presented below. -It is implemented as a class which, when instantiated, becomes a model -instance. - -.. code-block:: python - :linenos: - - import datetime - - class BlogEntry(object): - def __init__(self, title, body, author): - self.title = title - self.body = body - self.author = author - self.created = datetime.datetime.now() - -A model constructor may be essentially any Python object which is -callable, and which returns a model instance. In the above example, -the ``BlogEntry`` class can be called, returning a model instance. - -.. index:: - single: model interfaces - -.. _models_which_implement_interfaces: - -Model Instances Which Implement Interfaces ------------------------------------------- - -Model instances can optionally be made to implement an -:term:`interface`. An interface is used to tag a model object with a -"type" that can later be referred to within :term:`view -configuration`. - -Specifying an interface instead of a class as the ``context`` or -``containment`` arguments within :term:`view configuration` statements -effectively makes it possible to use a single view callable for more -than one class of object. If your application is simple enough that -you see no reason to want to do this, you can skip reading this -section of the chapter. - -For example, here's some code which describes a blog entry which also -declares that the blog entry implements an :term:`interface`. - -.. code-block:: python - :linenos: - - import datetime - from zope.interface import implements - from zope.interface import Interface - - class IBlogEntry(Interface): - pass - - class BlogEntry(object): - implements(IBlogEntry) - def __init__(self, title, body, author): - self.title = title - self.body = body - self.author = author - self.created = datetime.datetime.now() - -This model consists of two things: the class which defines the model -constructor (above as the class ``BlogEntry``), and an -:term:`interface` attached to the class (via an ``implements`` -statement at class scope using the ``IBlogEntry`` interface as its -sole argument). - -The interface object used must be an instance of a class that inherits -from :class:`zope.interface.Interface`. - -A model class may *implement* zero or more interfaces. You specify -that a model implements an interface by using the -:func:`zope.interface.implements` function at class scope. The above -``BlogEntry`` model implements the ``IBlogEntry`` interface. - -You can also specify that a *particular* model instance provides an -interface, as opposed to its class as above, which implies that all -instances do. To do so, use the :func:`zope.interface.directlyProvides` -function: - -.. code-block:: python - :linenos: - - from zope.interface import directlyProvides - from zope.interface import Interface - - class IBlogEntry(Interface): - pass - - class BlogEntry(object): - def __init__(self, title, body, author): - self.title = title - self.body = body - self.author = author - self.created = datetime.datetime.now() - - entry = BlogEntry('title', 'body', 'author') - directlyProvides(entry, IBlogEntry) - -:func:`zope.interface.directlyProvides` will replace any existing -interface that was previously provided by an instance. If a model -object already has instance-level interface declarations that you -don't want to replace, use the :func:`zope.interface.alsoProvides` -function: - -.. code-block:: python - :linenos: - - from zope.interface import alsoProvides - from zope.interface import directlyProvides - from zope.interface import Interface - - class IBlogEntry1(Interface): - pass - - class IBlogEntry2(Interface): - pass - - class BlogEntry(object): - def __init__(self, title, body, author): - self.title = title - self.body = body - self.author = author - self.created = datetime.datetime.now() - - entry = BlogEntry('title', 'body', 'author') - directlyProvides(entry, IBlogEntry1) - alsoProvides(entry, IBlogEntry2) - -:func:`zope.interface.alsoProvides` will augment the set of interfaces -directly provided by an instance instead of overwriting them like -:func:`zope.interface.directlyProvides` does. - -For more information about how model interfaces can be used by view -configuration, see :ref:`using_model_interfaces`. - -.. index:: - single: model graph - single: traversal graph - single: object graph - single: container nodes - single: leaf nodes - -Defining a Graph of Model Instances for Traversal -------------------------------------------------- - -When :term:`traversal` is used (as opposed to a purely :term:`url -dispatch` based application), :app:`Pyramid` expects to be able to -traverse a graph composed of model instances. Traversal begins at a -root model instance, and descends into the graph recursively via each -found model's ``__getitem__`` method. :app:`Pyramid` imposes the -following policy on model instance nodes in the graph: - -- Container nodes (i.e., nodes which contain other nodes) must supply - a ``__getitem__`` method which is willing to resolve a unicode name - to a subobject. If a subobject by that name does not exist in the - container, ``__getitem__`` must raise a :exc:`KeyError`. If a - subobject by that name *does* exist, the container should return the - subobject (another model instance). - -- Leaf nodes, which do not contain other nodes, must not - implement a ``__getitem__``, or if they do, their ``__getitem__`` - method must raise a :exc:`KeyError`. - -See :ref:`traversal_chapter` for more information about how traversal -works against model instances. - -.. index:: - pair: location-aware; model - -.. _location_aware: - -Location-Aware Model Instances ------------------------------- - -Applications which use :term:`traversal` to locate the :term:`context` -of a view must ensure that the model instances that make up the model -graph are "location aware". - -In order for :app:`Pyramid` location, security, URL-generation, and -traversal functions (i.e., functions in :ref:`location_module`, -:ref:`traversal_module`, :ref:`url_module` and some in -:ref:`security_module` ) to work properly against the model instances in -an object graph, all nodes in the graph must be :term:`location` -aware. -This means they must have two attributes: ``__parent__`` and -``__name__``. - -The ``__parent__`` attribute should be a reference to the node's -parent model instance in the graph. The ``__name__`` attribute should -be the name that a node's parent refers to the node via -``__getitem__``. - -The ``__parent__`` of the root object should be ``None`` and its -``__name__`` should be the empty string. For instance: - -.. code-block:: python - :linenos: - - class MyRootObject(object): - __name__ = '' - __parent__ = None - -A node returned from the root item's ``__getitem__`` method should have -a ``__parent__`` attribute that is a reference to the root object, and -its ``__name__`` attribute should match the name by which it is -reachable via the root object's ``__getitem__``. A container under the -root should have a ``__getitem__`` that returns objects with a -``__parent__`` attribute that points at the container, and these -subobjects should have a ``__name__`` attribute that matches the name by -which they are retrieved from the container via ``__getitem__``. -This pattern continues recursively down the graph. - -The ``__parent__`` attributes of each node form a linked list -that points "upward" toward the root. This is analogous to the -`..` entry in filesystem directories. If you follow the ``__parent__`` -values from any node in the traversal graph, you will eventually -come to the root node, just like if you keep executing the -``cd ..`` filesystem command, eventually you will reach the -filesystem root directory. - -.. warning:: If your root model object has a ``__name__`` argument - that is not ``None`` or the empty string, URLs returned by the - :func:`pyramid.url.model_url` function and paths generated by - the :func:`pyramid.traversal.model_path` and - :func:`pyramid.traversal.model_path_tuple` APIs will be - generated improperly. The value of ``__name__`` will be prepended - to every path and URL generated (as opposed to a single leading - slash or empty tuple element). - -.. sidebar:: Using :mod:`pyramid_traversalwrapper` - - If you'd rather not manage the ``__name__`` and ``__parent__`` - attributes of your models "by hand", an add-on package named - :mod:`pyramid_traversalwrapper` can help. - - In order to use this helper feature, you must first install the - :mod:`pyramid_traversalwrapper` package (available via PyPI), then register - its ``ModelGraphTraverser`` as the traversal policy, rather than the - default :app:`Pyramid` traverser. The package contains instructions for - doing so. - - Once :app:`Pyramid` is configured with this feature, you will no - longer need to manage the ``__parent__`` and ``__name__`` attributes - on graph objects "by hand". Instead, as necessary, during traversal - :app:`Pyramid` will wrap each object (even the root object) in a - ``LocationProxy`` which will dynamically assign a ``__name__`` and a - ``__parent__`` to the traversed object (based on the last traversed - object and the name supplied to ``__getitem__``). The root object - will have a ``__name__`` attribute of ``None`` and a ``__parent__`` - attribute of ``None``. - -.. index:: - single: model API functions - single: url generation (traversal) - -:app:`Pyramid` API Functions That Act Against Models -------------------------------------------------------- - -A model instance is used as the :term:`context` provided to a view. See -:ref:`traversal_chapter` and :ref:`urldispatch_chapter` for more information -about how a model instance becomes the context. - -The APIs provided by :ref:`traversal_module` are used against model -instances. These functions can be used to find the "path" of a model, -the root model in an object graph, or generate a URL to a model. - -The APIs provided by :ref:`location_module` are used against model -instances. These can be used to walk down an object graph, or -conveniently locate one object "inside" another. - -Some APIs in :ref:`security_module` accept a model object as a -parameter. For example, the -:func:`pyramid.security.has_permission` API accepts a "context" (a -model object) as one of its arguments; the ACL is obtained from this -model or one of its ancestors. Other APIs in the -:mod:`pyramid.security` module also accept :term:`context` as an -argument, and a context is always a model. - |
