Zope3: comment ajouter un objet proprement.

Posté le 13/05/2006 sous zope3

A première vue, le plus simple moyen d'ajouter un objet dans un dossier serait le suivant:

>>> from zope.app.folder import Folder
>>> mycontent = Folder()
>>> mycontent.__name__ = 'myid'

>>> folder = Folder()
>>> folder['myid'] = mycontent

Cela fonctionne bien. L'inconvénient est que l'on perds toute la machinerie de zope.

J'ai donc cherché un moyen plus propre d'ajouter un objet. J'en suis arrivé a la conclusion que le mieux est d'utiliser une vue Adding. Ce qui nous donne:

from zope.app.container.browser.adding import Adding
from zope.app.event.objectevent import ObjectCreatedEvent
from contents import MyContent

class MyContentView(BrowserView):
    """ a simple view """

    def add(self):
        view = Adding( self.context, self.request )
        context = view.add( MyContent() )
        notify(ObjectCreatedEvent(context))

Par ce moyen, on créer un objet proprement. Par exemple l'id seras généré à l'aide d'un INameChooser, etc.

Utilisation de INameChooser

Posté le 02/05/2006 sous zope3

Pour un blog, on veut pouvoir créer des post sans avoir à définir leurs ids.

On en fait de même pour les folders. Voici le principe:

  • Si nous sommes dans le dossier racine, on créé un dossier pour l'année.
  • Si on est dans une année, on créé un dossier pour le mois
  • Si on est dans un mois, on créé une post qui a son id basé sur le jour et l'heure courante.

Dans Zope cela donnes:

>>> from zope.app.container.interfaces import INameChooser
>>> from zope.app.container.contained import NameChooser
>>> import datetime

>>> class IWeblog(zope.interface.Interface):pass

>>> class WeblogNameChooser(NameChooser):
...     zope.interface.implements(INameChooser)
...     zope.component.adapts(IWeblog)
...     def __init__(self,context):
...         self.context = context
...     def chooseName(self,name,object):
...         container = self.context
...         now = datetime.datetime.now()
...         year = now.strftime('%Y')
...         month = now.strftime('%m')
...         if 'log' in str(container.__name__):
...             return unicode(year)
...         elif str(container.__name__) == year:
...             return unicode(month)
...         elif str(container.__name__) == month:
...             return unicode(now.strftime('%Y%m%d%H'))
...         return NameChooser.chooseName(self,name,object)

L'interface INameChooser définit un adapter qui permet de modifier la façon dont zope génère ses ids. Ici, on utilise la date et l'id du parent pour générer l'id de nos objets.

On peut tester que l'exemple fonctionne bien:

>>> now = datetime.datetime.now()
>>> year = now.strftime('%Y')
>>> month = now.strftime('%m')

On créé un folder root:

>>> from zope.app.folder import Folder
>>> folder = Folder()
>>> folder.__name__ = 'weblog'

On instancie notre INameChooser et on vérifie qu'il génère bien une année:

>>> chooser = WeblogNameChooser(folder)
>>> chooser.chooseName('',None) == unicode(year)
True

Même exemple. Mais ici, le chooser renvois le mois:

>>> folder.__name__ = unicode(year)
>>> chooser = WeblogNameChooser(folder)
>>> chooser.chooseName('',None) == unicode(month)
True

Bien que l'interface soit définit pour un dossier, elle est utilisée pour définir l'id de l'objet que l'on ajoute dans un dossier et non l'id du dossier lui même. C'est ainsi que l'on peut aussi définir l'id d'un post.

On peut donc aussi basé le choix de l'id sur le type de contenu que l'on ajoutes dans le dossier.

On voit ici la puissance des interfaces de Zope3 car il est possible par ce moyen de redéfinir la façon dont seras généré l'id de n'importe qul objet simplement en implémentant un NameChooser pour l'interface de ces objets.