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.
|