add keytable stuff to grid-like field definitions
This commit is contained in:
parent
3e5b4d2bff
commit
4c2f79d929
3 changed files with 130 additions and 23 deletions
|
@ -2,8 +2,6 @@
|
|||
Schema and Field Management
|
||||
===========================
|
||||
|
||||
($Id$)
|
||||
|
||||
>>> from cybertools.composer.schema import Schema
|
||||
>>> from cybertools.composer.schema import Field
|
||||
|
||||
|
@ -193,3 +191,58 @@ Macros / renderers
|
|||
[u'field', u'field_spacer', u'fields', u'form', u'input_checkbox',
|
||||
u'input_date', u'input_dropdown', u'input_fileupload', u'input_html',
|
||||
u'input_list', u'input_password', u'input_textarea', u'input_textline']
|
||||
|
||||
|
||||
Special Field Types
|
||||
===================
|
||||
|
||||
Grids, Records, Key Tables
|
||||
--------------------------
|
||||
|
||||
>>> from cybertools.composer.schema.grid.field import KeyTableFieldInstance
|
||||
|
||||
>>> ktfield = Field('data')
|
||||
>>> ktfield.column_types = [zope.schema.Text(__name__='key', title=u'Key',),
|
||||
... zope.schema.Text(__name__='value', title=u'Value')]
|
||||
|
||||
>>> ktfi = KeyTableFieldInstance(ktfield)
|
||||
>>> ktfi.unmarshall([dict(key='0001', value='First row')])
|
||||
{u'0001': [u'First row']}
|
||||
|
||||
>>> ktfi.marshall({u'0001': [u'First row']})
|
||||
[{'value': u'First row', 'key': u'0001'}]
|
||||
|
||||
Now with some real stuff, using a field instance that takes the column types
|
||||
from the context object of the edit form.
|
||||
|
||||
>>> from cybertools.composer.schema.grid.interfaces import KeyTable
|
||||
>>> from cybertools.composer.schema.grid.field import \
|
||||
... ContextBasedKeyTableFieldInstance
|
||||
>>> component.provideAdapter(ContextBasedKeyTableFieldInstance, name='keytable')
|
||||
|
||||
>>> class IDataTable(Interface):
|
||||
... title = zope.schema.TextLine(title=u'Title', required=False)
|
||||
... columnNames = zope.schema.List(title=u'Column Names', required=False)
|
||||
... data = KeyTable(title=u'Data', required=False)
|
||||
>>> IDataTable['columnNames'].nostore = True
|
||||
|
||||
>>> class DataTable(object):
|
||||
... implements(IDataTable)
|
||||
... def __init__(self, title, columnNames):
|
||||
... self.title = title
|
||||
... self.columnNames = columnNames
|
||||
|
||||
>>> dt = DataTable('Account Types', ['identifier', 'label', 'info'])
|
||||
|
||||
>>> input = dict(title='Account Types',
|
||||
... columnNames=['identifier', 'label', 'info'],
|
||||
... data=[dict(identifier='0001', label='Standard', info='')],
|
||||
... action='update')
|
||||
>>> form = Form(dt, TestRequest(form=input))
|
||||
>>> form.interface = IDataTable
|
||||
>>> form.nextUrl = 'dummy_url'
|
||||
>>> form.update()
|
||||
False
|
||||
|
||||
>>> dt.data
|
||||
{u'0001': [u'Standard', u'']}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2009 Helmut Merz helmutm@cy55.de
|
||||
# Copyright (c) 2011 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -18,8 +18,6 @@
|
|||
|
||||
"""
|
||||
Field and field instance classes for grids.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope import component
|
||||
|
@ -30,7 +28,7 @@ from zope.cachedescriptors.property import Lazy
|
|||
import zope.schema
|
||||
|
||||
from cybertools.composer.schema.factory import createField
|
||||
from cybertools.composer.schema.field import ListFieldInstance
|
||||
from cybertools.composer.schema.field import Field, ListFieldInstance
|
||||
from cybertools.composer.schema.interfaces import IField, IFieldInstance
|
||||
from cybertools.composer.schema.interfaces import fieldTypes, undefined
|
||||
from cybertools.util.format import toStr, toUnicode
|
||||
|
@ -91,6 +89,13 @@ class GridFieldInstance(ListFieldInstance):
|
|||
return []
|
||||
result = []
|
||||
rows = json.loads(value)['items']
|
||||
for row in rows:
|
||||
item = self.unmarshallRow(row)
|
||||
if item:
|
||||
result.append(item)
|
||||
return result
|
||||
|
||||
def dummy(self):
|
||||
for row in rows:
|
||||
item = {}
|
||||
empty = True
|
||||
|
@ -106,6 +111,18 @@ class GridFieldInstance(ListFieldInstance):
|
|||
result.append(item)
|
||||
return result
|
||||
|
||||
def unmarshallRow(self, row):
|
||||
item = {}
|
||||
for fi in self.columnFieldInstances:
|
||||
value = fi.unmarshall(row[fi.name])
|
||||
if isinstance(value, basestring):
|
||||
value = value.strip()
|
||||
if fi.default is not None:
|
||||
if value == fi.default:
|
||||
continue
|
||||
item[fi.name] = value
|
||||
return item
|
||||
|
||||
|
||||
class RecordsFieldInstance(GridFieldInstance):
|
||||
|
||||
|
@ -123,19 +140,49 @@ class RecordsFieldInstance(GridFieldInstance):
|
|||
value = []
|
||||
result = []
|
||||
for row in value:
|
||||
item = {}
|
||||
empty = True
|
||||
for fi in self.columnFieldInstances:
|
||||
value = row[fi.name]
|
||||
if isinstance(value, basestring):
|
||||
value = value.strip()
|
||||
value = fi.unmarshall(value)
|
||||
item[fi.name] = value
|
||||
if fi.default is not None:
|
||||
if value and value != fi.default:
|
||||
empty = False
|
||||
elif value:
|
||||
empty = False
|
||||
if not empty:
|
||||
item = self.unmarshallRow(row)
|
||||
if item:
|
||||
result.append(item)
|
||||
return result
|
||||
|
||||
|
||||
class KeyTableFieldInstance(RecordsFieldInstance):
|
||||
|
||||
@Lazy
|
||||
def keyName(self):
|
||||
return self.columnTypes[0].name
|
||||
|
||||
@Lazy
|
||||
def dataNames(self):
|
||||
return [f.name for f in self.columnTypes[1:]]
|
||||
|
||||
def marshall(self, value):
|
||||
result = []
|
||||
if not value:
|
||||
return result
|
||||
for k, v in value.items():
|
||||
item = {self.keyName: k}
|
||||
for idx, name in enumerate(self.dataNames):
|
||||
item[name] = v[idx]
|
||||
result.append(item)
|
||||
return result
|
||||
|
||||
def unmarshall(self, value):
|
||||
if not value:
|
||||
value = {}
|
||||
result = {}
|
||||
for row in value:
|
||||
item = self.unmarshallRow(row)
|
||||
if item:
|
||||
result[item.pop(self.keyName)] = [item.get(name)
|
||||
for name in self.dataNames]
|
||||
return result
|
||||
|
||||
|
||||
class ContextBasedKeyTableFieldInstance(KeyTableFieldInstance):
|
||||
|
||||
@Lazy
|
||||
def columnTypes(self):
|
||||
obj = self.clientInstance.context
|
||||
return [Field(name) for name in obj.columnNames]
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2009 Helmut Merz helmutm@cy55.de
|
||||
# Copyright (c) 2011 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -18,8 +18,6 @@
|
|||
|
||||
"""
|
||||
Grid field definition.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope import schema
|
||||
|
@ -50,3 +48,12 @@ class Records(Grid):
|
|||
u'A series of records or rows.',
|
||||
instanceName='records',))
|
||||
|
||||
|
||||
class KeyTable(Grid):
|
||||
|
||||
__typeInfo__ = ('keytable',
|
||||
FieldType('keytable', 'keytable',
|
||||
u'A dictionary of records or rows the first '
|
||||
u'column of which represents the key.',
|
||||
instanceName='keytable',))
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue