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:
parent
74b9efffc3
commit
66faec4a38
7 changed files with 82 additions and 35 deletions
|
@ -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
|
||||
|
|
|
@ -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__)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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.')
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue