Zope 3 et le Catalogue

Publié le 02 mai 2009 par Mikebrant

Mais je suis quand même un peu meilleur que Zorro.

Bon ça faisait longtemps (non le blog n’est pas mort mais je suis sur un projet zope 3).
D’ailleurs le 29 avril le blog a fêté sa première année(ouais tout le monde en a rien à foutre mais bon).

On va voir aujourd’hui comment utiliser SIMPLEMENT le catalogue avec Zope 3.
Bon alors pratiquemment tout le monde doit savoir le faire, mais bon moi je ne savais pas.

Ça sert à quoi un catalogue ?
En gros, un catalogue va nous permettre d’indexer des attributs/méthodes de nos objets afin de pouvoir les rechercher super vite.

exemple:

J’ai une Voiture rouge (à vrai dire j’ai même pas le permis mais bon), que j’emmène à un parking.
Je dis au voiturier que ma Voiture est rouge.

Quand je voudrais la reprendre :
le voiturier, au lieu de se ballader dans toutes les allés du parking, afin de trouver quelle est la Voiture rouge parmis toutes les autres,
va simplement regarder dans son registre où est la Voiture rouge.

Et du coup, il gagne plein de temps.

Notre application Zope 3 se nomme Racine et implémente IRacine.
Et on a vouloir chercher des objets  Ecole  (la classe Ecole implémentant IEcole).

Voici ce que ça donne:

interfaces.py :

from zope.app.component.interfaces import IPossibleSite
from zope.schema import Field
from zope.app.container.interfaces import IContained,IContainer
from zope.app.container.constraints import ItemTypePrecondition, ContainerTypesConstraint

class IEcole(IContained):
   «  »"Une école quoi »" »
  
   nom = Field(
   title=u »Nom »,
   required=True
   )

class IRacine(IPossibleSite,IContainer):
   «  »"Contiendra l’application web, c’est le ‘site’ «  »"
  
  
   def __setitem__(nom,objet):
   «  »"ajoute un objet »" »
   pass
  
   __setitem__.precondition = ItemTypePrecondition(IEcole)#il ne pourra ajouter que des objets implémentant IEcole

class IEcoleContenuDans(IContained):
   «  »"contrainte pour pouvoir ajouter uniquement une Ecole dans Racine »" »
  
   __parent__ = Field(
   constraint = ContainerTypesConstraint(IRacine)
   )

Bon je ne l’explique pas vu que c’est pas le but du billet (et puis de toute manière ya pas grand chose à commenter, c’est totalement trivial).
Et maintenant voici les modèles Racine et Ecole :

Modeles/Racine.py :

#-*- coding:Utf-8 -*-

from zope.interface import implements
from zope.app.component.site import SiteManagerContainer
from zope.app.container.btree import BTreeContainer
from saucisson.interfaces import IRacine

class Racine(SiteManagerContainer,BTreeContainer):
   __doc__ = IRacine.__doc__
  
   implements(IRacine)

Modeles/Ecole.py :

#-*- coding:Utf-8 -*-
from zope.interface import implements
from zope.app.container.contained import Contained
from saucisson.interfaces import IEcole,IEcoleContenuDans

class Ecole(Contained):
   __doc__ = IEcole.__doc__
  
   implements(IEcole,IEcoleContenuDans)
  
   def __init__(self,nom):
   self.nom = nom

Même remarque qu’au dessus.

Bon maintenant il nous faut rajouter une ligne dans le configure.zcml principal :

<subscriber handler= ».creationSite.creationSite » />

Et voici creationSite.py :

#-*- coding:Utf-8 -*-
from zope.component import adapter
from zope.app.container.interfaces import IObjectAddedEvent
from zope.app.component.site import LocalSiteManager
#interfaces du projet
from saucisson.interfaces import IRacine
from saucisson.interfaces import IEcole
#catalogue
from zope.app.catalog.catalog import Catalog
from zope.app.catalog.interfaces import ICatalog
from zope.app.catalog.text import TextIndex
#IntId
from zope.app.intid.interfaces import IIntIds
from zope.app.intid import IntIds

@adapter(IRacine, IObjectAddedEvent)
def creationSite(site, evenement):

   sm = LocalSiteManager(site)
   catalogue = Catalog()
   sm ['catalogue'] = catalogue
  
   if sm .queryUtility(IIntIds) is None:
   uid = IntIds()
   sm ['uid'] = uid
   sm .registerUtility(uid, IIntIds)

   #index de l’école
   sm ['catalogue']['nomEcole'] = TextIndex(‘nom‘,IEcole)
   set on en fait un utilitaire
   sm .registerUtility(sm['catalogue'],ICatalog)

La je vais expliquer.
le subscriber nous permet d’éxécuter notre fonctioncreationSite()  lors que Racine sera instancié.
Dans creationSite(), on fait de Racine un  » vrai site » via LocalSiteManager().
Ensuite on instancie Catalog,et on le rajoute dans notre site.

Après, on doit ajouter dans notre site un objet de type IntIds et en faire un utilitaire puisque c’est lui qui va se charger de nous filer les id pour indexer nos objets.

Maintenant, on ajoute un index dans notre catalogue :
nomEcole, qui va indexer toutes les valeurs de l’attribut nom des objets implémentant IEcole.
Enfin, notre catalogue devient un utilitaire.

Et voilà, notre catalogue est créé et marche.

Comment on indexe un attribut d’un objet ?
Très simplement.

Voici ce que vous devez rajouter dans votre .py de votre vue (par exemple) :

from zope.app.catalog.interfaces import ICatalog
from zope.app.intid.interfaces import IIntIds
from zope.component import queryUtility

ecole = Ecole(« Les Maristes »)
[...]
catalogue = queryUtility(ICatalog,context=self.context)
index = queryUtility(IIntIds,context=self.context)

index
= index.queryId(ecole)
catalogue.index_doc(index,ecole)

On commence par récupérer nos deux utilitaires via queryUtility().

Ensuite on associe un id à notre objet via l’utilitaire IIntIds.
Puis on indexe notre objet via index_doc(), en n’oubliant pas de lui passer l’id.

Comment on recherche dans le catalogue?
Très simplement.
Voici un bout de code :

from zope.component import queryUtility
from zope.app.catalog.interfaces import ICatalog

catalogue = queryUtility(ICatalog)

resultats = catalogue.searchResults(nomEcole=’Les Maristes’)
resultats = [i for i in resultats]
return resultats

Alors,
on récupère notre utilitaire catalogue.

Après on recherche toutes les écoles contenant comme nom « Les Maristes » via l’index : nomEcole .

Viens boire Un p’tit coup à la maison de list compréhensions et c’est fini.

J’ai fait ce billet très rapidement, alors si ya des ratages, des questions, n’hésitez pas (enfin faut pas que la question soit trop poussée non plus hein )