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

View file

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

View file

@ -192,6 +192,8 @@ class IField(IComponent):
'field instance.') 'field instance.')
undefined = object() # A marker for a field instance value not set.
class IFieldInstance(Interface): class IFieldInstance(Interface):
""" An adapter for checking and converting data values coming """ An adapter for checking and converting data values coming
from or being displayed on an external system (like a browser form). from or being displayed on an external system (like a browser form).
@ -201,18 +203,28 @@ class IFieldInstance(Interface):
name = Attribute('Field name.') name = Attribute('Field name.')
change = Attribute('A tuple ``(oldValue, newValue)`` or None.') change = Attribute('A tuple ``(oldValue, newValue)`` or None.')
errors = Attribute('A sequence of error infos.') errors = Attribute('A sequence of error infos.')
severity = Attribute("An integer giving a state or error " severity = Attribute('An integer giving a state or error '
"code, 0 meaning 'OK'.") '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): def getRawValue(data, key, default=None):
""" Extract a raw value for the field from the data given """ Extract a raw value for the field from the data given
using the key; if no corresponding value is found return 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): def marshall(value):
""" Return a string (possibly unicode) representation of the """ 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): def display(value):
@ -220,9 +232,9 @@ class IFieldInstance(Interface):
value given that may be used for presentation. value given that may be used for presentation.
""" """
def unmarshall(rawValue): def unmarshall(inputValue):
""" Return the internal (real) value corresponding to the """ Return the internal (real) value corresponding to the
raw value given. input (external, raw) value given.
""" """
def validate(value, data=None): def validate(value, data=None):

View file

@ -7,15 +7,12 @@ A Basic API for Reports and Listings
TO DO... TO DO...
>>> from zope import component >>> from zope import component
>>> from zope.interface import directlyProvides
Listings Listings
======== ========
>>> from cybertools.reporter.data import DataSource >>> 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 Let's start with the Person class from the cybertools.organize package - we will
then provide a listing of persons... 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('-')])) >>> persons = DataSource([Person(f, s, date(*[int(d) for d in b.split('-')]))
... for f, s, b in pdata]) ... for f, s, b in pdata])
>>> from cybertools.reporter.resultset import ResultSet, ContentRow
>>> from cybertools.reporter.interfaces import IResultSet, IRow
>>> component.provideAdapter(ResultSet) >>> component.provideAdapter(ResultSet)
>>> rset = IResultSet(persons) >>> component.provideAdapter(ContentRow, provides=IRow)
>>> 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.
>>> from cybertools.composer.schema.schema import Schema >>> from cybertools.composer.schema.schema import Schema
>>> from cybertools.composer.schema.field import Field >>> from cybertools.composer.schema.field import Field
>>> rset.schema = Schema(Field(u'firstName'), Field(u'lastName'), Field(u'birthDate')) >>> from cybertools.composer.schema.field import FieldInstance, DateFieldInstance
>>> r1 = rset.rows.next() >>> component.provideAdapter(FieldInstance)
>>> [c.text for c in r1.cells] >>> component.provideAdapter(DateFieldInstance, name='date')
[u'Smith', u'John', u'1956-08-01']
>>> 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 For the browser presentation we can also use a browser view providing
the result set with extended attributes: 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 The reporter package also includes facilities for sorting the rows in a
result set and splitting a result into batches. result set and splitting a result into batches.
Sorting Sorting
------- =======
Batching Batching

View file

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

View file

@ -55,6 +55,7 @@ class IRow(Interface):
class ICell(Interface): class ICell(Interface):
""" A single cell of a listing or table. """ A single cell of a listing or table.
""" """
# TODO: replace Cell by FieldInstance
field = Attribute(u'The schema field the cell belongs to.') 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 # TODO: move the generic stuff to cybertools.reporter.result
from zope.cachedescriptors.property import Lazy
from zope.component import adapts 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 IDataSource
from cybertools.reporter.interfaces import IResultSet, IRow, ICell from cybertools.reporter.interfaces import IResultSet, IRow, ICell
class Cell(object): class Cell(object):
# TODO: replace Cell by FieldInstance
implements(ICell) implements(ICell)
@ -61,7 +64,7 @@ class Cell(object):
url = urlTitle = u'' url = urlTitle = u''
class Row(object): class Row(Instance):
implements(IRow) implements(IRow)
@ -69,17 +72,33 @@ class Row(object):
self.context = context self.context = context
self.resultSet = resultSet self.resultSet = resultSet
@property @Lazy
def schema(self): def schema(self):
return self.resultSet.schema return self.resultSet.schema
@Lazy
def fields(self):
return self.schema.fields
@property @property
def cells(self): def cells(self):
for f in self.resultSet.schema.fields: for f in self.schema.fields:
rf = f.renderFactory or Cell rf = f.renderFactory or Cell
yield rf(f, getattr(self.context, f.name), self) 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): class ResultSet(object):
implements(IResultSet) implements(IResultSet)
@ -96,3 +115,9 @@ class ResultSet(object):
for o in iter(self.context): for o in iter(self.context):
yield Row(o, self) 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