[Grok-dev] schema.List returns a list, but is it persistent?

Uli Fouquet uli at gnufix.de
Tue Sep 1 02:33:39 EDT 2009


Hi there,

Leonardo Rochael Almeida wrote:

> On Fri, Aug 28, 2009 at 14:40, Kevin Teague<kevin at bud.ca> wrote:
> > I think instead of writing this:
> >
> >  tags = schema.List(title=u"Content Tags", default = [])
> >
> > You could write this?
> >
> >  tags = schema.List(title=u"Content Tags", default =
> > persistent.list.PersistentList())
> 
> The problem with this approach, besides the "WrongType error" is that
> only the default value would be a persistent list. As soon as a form
> is submitted with a valid, but different, value, this value would be a
> regular list.

Right, it would also mean that different types might be used during the
lists lifetime. That's what the WrongType error wants to warn one
against (although you can change the type 'behind the back' of the
schema as Sebastian did in former examples).

Just for the logs, you could get rid of the WrongType by defining a new
schema like this (Leo already mentioned the ``_type`` attribute)::

  import grok
  from persistent.list import PersistentList
  from zope import schema

  class IPersistentList(schema.interfaces.IList):
    """A persistent list is different from an ordinary one.
    """
    pass

  class PersistentSchemaList(schema.List):
     grok.implements(IPersistentList)
    _type = PersistentList

  # ...to be continued below.

With this you can do::

  tags = PersistentSchemaList(title=u"Content Tags", 
                              default=PersistentList())

in any schema you define.

You will, however run into problems when you want this field to be
rendered with standard input forms (grok.AddForm, grok.EditForm, etc.).
That's because there are yet no widgets defined for lists that are in
fact PersistentList instances. Widgets, similar to schema fields in that
respect, check value types against a given 'built-in' type (also set by
``_type`` attribute) and raise exceptions if both differ. In other
words: with the code above only, you will create forms with widgets that
return non-persistent lists and whose values therefore will be refused.

But defining such a widget is not too difficult. You only have to know,
where all the interfaces and bases are defined. Something like this
might work::

  # example above continued...

  from zope.app.form.browser.sequencewidget import ListSequenceWidget
  from zope.app.form.browser.interfaces import ISimpleInputWidget
  from zope.publisher.interfaces.browser import IBrowserRequest

  class PersistentListSequenceWidget(ListSequenceWidget):
      """A widget that renders persistent lists.
      """
      _type = PersistentList

  # Register the above class as multi adapter...
  @grok.adapter(IPersistentList,
                schema.interfaces.IField,
                IBrowserRequest)
  @grok.implementer(ISimpleInputWidget)
  def plist_widget(thelist, field, request):
      """Return a simple input widget for a (plist, field, req) tuple.

      This widget will return PersistentLists and raise errors if 
      the list given is not persistent.
      """
      return PersistentListSequenceWidget(thelist, field, request)

This might look like much code, but it's much less if you leave out
comments and afterwards you should be able to use persistent lists
out-of-the-box from all your self-defined schemas without any hacks.
Also applyData can be used as-is.

Persistent dicts are a bit more complicated to implement, I think.

The above code is only a (certainly improvable) sketch. I do not use it
in my own code.

> > This is simpler than making a new schema field type. Not 100% sure how
> > it works with applyData, but I think it should work? Annoyingingly
> > though, the above will throw a WrongType error, but it does look like
> > a fix was proposed for this (no one objected, but it also looks like
> > the fix wasn't made either):

Hm, maybe this fix wasn't made because it would mean to mix-up
persistent and non-persistent things? Furthermore you'd also need
appropriate widgets. As shown above changing the _type attribute only is
not enough for many use cases. In the end the fix would probably lead to
even more confusion.

Best regards,

-- 
Uli

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Dies ist ein digital signierter Nachrichtenteil
Url : http://mail.zope.org/pipermail/grok-dev/attachments/20090901/8eaf46b8/attachment.bin 


More information about the Grok-dev mailing list