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