extend/adapt result set to use client instance objects for rows, using the applyTemplate() method for retrieving and formatting cell data

git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@2743 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2008-07-07 17:57:38 +00:00
parent 74b9efffc3
commit 66faec4a38
7 changed files with 82 additions and 35 deletions

View file

@ -33,7 +33,7 @@ from zope.i18n.locales import locales
from cybertools.composer.base import Component
from cybertools.composer.schema.interfaces import IField, IFieldInstance
from cybertools.composer.schema.interfaces import fieldTypes
from cybertools.composer.schema.interfaces import fieldTypes, undefined
from cybertools.composer.schema.schema import formErrors
from cybertools.util.format import toStr, toUnicode
@ -61,7 +61,8 @@ class Field(Component):
def __init__(self, name, title=None, fieldType='textline', **kw):
assert name
self.__name__ = name
title = title or u''
#title = title or u''
title = title or name
self.fieldType = fieldType
super(Field, self).__init__(title, __name__=name, **kw)
self.title = title
@ -127,6 +128,7 @@ class FieldInstance(object):
adapts(IField)
clientInstance = None
value = undefined
def __init__(self, context):
self.context = context

View file

@ -39,6 +39,7 @@ class Instance(BaseInstance):
aspect = 'schema.editor.default'
template = None
view = None
def applyTemplate(self, *args, **kw):
#result = dict(__name__=self.context.__name__)

View file

@ -192,6 +192,8 @@ class IField(IComponent):
'field instance.')
undefined = object() # A marker for a field instance value not set.
class IFieldInstance(Interface):
""" An adapter for checking and converting data values coming
from or being displayed on an external system (like a browser form).
@ -201,18 +203,28 @@ class IFieldInstance(Interface):
name = Attribute('Field name.')
change = Attribute('A tuple ``(oldValue, newValue)`` or None.')
errors = Attribute('A sequence of error infos.')
severity = Attribute("An integer giving a state or error "
"code, 0 meaning 'OK'.")
severity = Attribute('An integer giving a state or error '
'code, 0 meaning OK.')
clientInstance = Attribute('An optional adapter to a client object that '
'provides or receives data processed by this field instance.')
value = Attribute ('May contain the current value of the field '
'for later reuse. Default is ``undefined``. '
'If the ``change`` attribute is set ``value`` should '
'be equal to ``change[1]``.')
def getRawValue(data, key, default=None):
""" Extract a raw value for the field from the data given
using the key; if no corresponding value is found return
the default.
the default. The value returned may then be turned
byt self.unmarshall() to the real (internal) value.
"""
def marshall(value):
""" Return a string (possibly unicode) representation of the
value given that may be used for editing.
value given that may be used for editing. In case of complex
or structured fields (list, mapping, object fields) the return
value may also be a structured object (typically a list or
mapping) built up form string (unicode) values.
"""
def display(value):
@ -220,9 +232,9 @@ class IFieldInstance(Interface):
value given that may be used for presentation.
"""
def unmarshall(rawValue):
def unmarshall(inputValue):
""" Return the internal (real) value corresponding to the
raw value given.
input (external, raw) value given.
"""
def validate(value, data=None):

View file

@ -7,15 +7,12 @@ A Basic API for Reports and Listings
TO DO...
>>> from zope import component
>>> from zope.interface import directlyProvides
Listings
========
>>> from cybertools.reporter.data import DataSource
>>> from cybertools.reporter.resultset import ResultSet
>>> from cybertools.reporter.interfaces import IResultSet
Let's start with the Person class from the cybertools.organize package - we will
then provide a listing of persons...
@ -29,38 +26,42 @@ then provide a listing of persons...
>>> persons = DataSource([Person(f, s, date(*[int(d) for d in b.split('-')]))
... for f, s, b in pdata])
>>> from cybertools.reporter.resultset import ResultSet, ContentRow
>>> from cybertools.reporter.interfaces import IResultSet, IRow
>>> component.provideAdapter(ResultSet)
>>> rset = IResultSet(persons)
>>> len(list(rset.rows))
3
As we have not yet provided a schema for the result set the rows are
empty.
>>> r1 = rset.rows.next()
>>> list(r1.cells)
[]
So let's assign a schema to the result set.
>>> component.provideAdapter(ContentRow, provides=IRow)
>>> from cybertools.composer.schema.schema import Schema
>>> from cybertools.composer.schema.field import Field
>>> rset.schema = Schema(Field(u'firstName'), Field(u'lastName'), Field(u'birthDate'))
>>> r1 = rset.rows.next()
>>> [c.text for c in r1.cells]
[u'Smith', u'John', u'1956-08-01']
>>> from cybertools.composer.schema.field import FieldInstance, DateFieldInstance
>>> component.provideAdapter(FieldInstance)
>>> component.provideAdapter(DateFieldInstance, name='date')
>>> rset = IResultSet(persons)
>>> rset.schema = Schema(Field(u'firstName'), Field(u'lastName'),
... Field(u'birthDate', fieldType='date'))
>>> rows = list(rset.getRows())
>>> len(rows)
3
>>> for r in rows:
... print r.applyTemplate()
{u'lastName': u'John', u'birthDate': '1956-08-01', u'firstName': u'Smith'}
{u'lastName': u'David', u'birthDate': '1972-12-24', u'firstName': u'Waters'}
{u'lastName': u'Carla', u'birthDate': '1981-10-11', u'firstName': u'Myers'}
For the browser presentation we can also use a browser view providing
the result set with extended attributes:
>>> #rsView = component.getMultiAdapter((context, TestRequest()), IBrowserView)
>>> #rsView = component.getMultiAdapter((rset, TestRequest()), IBrowserView)
The reporter package also includes facilities for sorting the rows in a
result set and splitting a result into batches.
Sorting
-------
=======
Batching

View file

@ -5,6 +5,11 @@
xmlns:browser="http://namespaces.zope.org/browser"
i18n_domain="zope">
<adapter
factory="cybertools.reporter.resultset.ContentRow"
provides="cybertools.reporter.interfaces.IRow"
/>
<include package=".browser" />
</configure>

View file

@ -55,6 +55,7 @@ class IRow(Interface):
class ICell(Interface):
""" A single cell of a listing or table.
"""
# TODO: replace Cell by FieldInstance
field = Attribute(u'The schema field the cell belongs to.')

View file

@ -25,15 +25,18 @@ $Id$
# TODO: move the generic stuff to cybertools.reporter.result
from zope.cachedescriptors.property import Lazy
from zope.component import adapts
from zope.interface import implements
from zope.interface import Interface, implements
from cybertools.composer.schema.schema import Schema
from cybertools.composer.schema import Schema
from cybertools.composer.schema.instance import Instance
from cybertools.reporter.interfaces import IDataSource
from cybertools.reporter.interfaces import IResultSet, IRow, ICell
class Cell(object):
# TODO: replace Cell by FieldInstance
implements(ICell)
@ -61,7 +64,7 @@ class Cell(object):
url = urlTitle = u''
class Row(object):
class Row(Instance):
implements(IRow)
@ -69,17 +72,33 @@ class Row(object):
self.context = context
self.resultSet = resultSet
@property
@Lazy
def schema(self):
return self.resultSet.schema
@Lazy
def fields(self):
return self.schema.fields
@property
def cells(self):
for f in self.resultSet.schema.fields:
for f in self.schema.fields:
rf = f.renderFactory or Cell
yield rf(f, getattr(self.context, f.name), self)
class ContentRow(Instance):
""" A row adapter for standard content objects.
"""
implements(IRow)
adapts(Interface)
@Lazy
def fields(self):
return self.template.fields
class ResultSet(object):
implements(IResultSet)
@ -96,3 +115,9 @@ class ResultSet(object):
for o in iter(self.context):
yield Row(o, self)
def getRows(self):
for o in iter(self.context):
row = IRow(o)
row.resultSet = self
row.template = self.schema
yield row