summaryrefslogtreecommitdiff
path: root/docs/tutorials/catalog/index.rst
blob: af31ef6b0f62eb794b42af3e70f1ace56f1af4e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
.. _catalog_tutorial:

Using :mod:`repoze.catalog` Within :mod:`repoze.bfg`
====================================================

:mod:`repoze.catalog` is a ZODB-based system that can be used to index
Python objects.  It also offers a query interface for retrieving
previously indexed data.  Those whom are used to Zope's "ZCatalog"
implementation will feel at home using :mod:`repoze.catalog`.

This tutorial assumes that you want a Zope-like setup.  For example,
it assumes you want to use a persistent ZODB object as your
:term:`root` object, and that the :mod:`repoze.catalog` catalog will
be an attribute of this root object.  It is further assumed that you
want the application to be based on :term:`traversal`.

#. Follow the :ref:`zodb_with_zeo` tutorial to get a system set up with
   ZODB and ZEO.  When you are finished, come back here.

#. Install the :mod:`repoze.catalog` software within your application's
   environment:

   .. code-block:: text
   
   $ easy_install repoze.catalog

#. Change your ZODB application's ``models.py`` file to look like the
   below:

   .. code-block:: python

       from repoze.folder import Folder
       from repoze.catalog.catalog import Catalog
       from repoze.catalog.document import DocumentMap
       from repoze.catalog.indexes.field import CatalogFieldIndex

       def get_title(object, default):
           title = getattr(object, 'title', '')
           if isinstance(title, basestring):
               # lowercase for alphabetic sorting
               title = title.lower()
           return title

       class Document(Folder):
           def __init__(self, title):
               self.title = title
               Folder.__init__(self)

       class Site(Folder):
           def __init__(self):
               self.catalog = Catalog()
               self.catalog.document_map = DocumentMap()
               self.update_indexes()
               Folder.__init__(self)

           def update_indexes(self):
               indexes = {
                   'title': CatalogFieldIndex(get_title),
               }

               catalog = self.catalog

               # add indexes
               for name, index in indexes.iteritems():
                   if name not in catalog:
                       catalog[name] = index

               # remove indexes
               for name in catalog.keys():
                   if name not in indexes:
                       del catalog[name]

#. Change the ``appmaker`` in your application's ``run.py`` to look
   something like the below:

   .. code-block:: python

       from myapp.models import Site

       def appmaker(root):
           if not 'site' in root:
               root['site'] = Site()
               transaction.commit()
           return root['site']

#.  We'll demonstrate how you might interact with a catalog from code
    by manipulating the database directly using the ``bfgshell``
    command in a terminal window:

    .. code-block:: text
       :linenos:

       [chrism@snowpro sess]$ ../bin/paster --plugin=repoze.bfg bfgshell \
              myapp.ini myapp
       Python 2.5.4 (r254:67916, Sep  4 2009, 02:12:16) 
       [GCC 4.2.1 (Apple Inc. build 5646)] on darwin
       Type "help" for more information. "root" is the BFG app root object.
       >>> from repoze.bfg.traversal import model_path
       >>> from myapp.models import Document
       >>> root['name'] = Document('title')
       >>> doc = root['name']
       >>> docid = root.catalog.document_map.add(model_path(doc))
       >>> root.catalog.index_doc(docid, doc)
       >>> import transaction
       >>> transaction.commit()
       >>> root.catalog.search(title='title')
       (1, IFSet([-787959756]))

#.  Add other indexes required by your application to the catalog
    within the ``update_indexes`` method of the ``Site`` object.
    Whenever an index is added or removed, invoke the
    ``update_indexes`` method of the site (the root object) from a
    script or from within a ``bfgshell`` session to update the set of
    indexes used by your application.

Read the :mod:`repoze.catalog` `documentation
<http://docs.repoze.org/catalog>`_ for further information about other
types of indexes to add, using the document map, and how to issue
queries using the catalog query API.

Note that in :term:`view` code, you should be able to get a hold of
the root object via the :func:`repoze.bfg.traversal.find_root` API.
The ``catalog`` attribute of that root object will represent the
catalog previously added.

.. note::

   The :mod:`repoze.folder` implementation sends events that can be
   intercepted with a :term:`subscriber` when documents are added and
   removed from a folder.  It is often useful to hook these events for
   the purpose of mutating the catalog when a new document is added or
   removed.  See the `repoze.folder documentation
   <http://docs.repoze.org/folder>`_ for more information.