[Checkins] SVN: z3c.form/branches/adamg-objectwidget/src/z3c/form/ major refactor between form.object and form.browser.object
Adam Groszer
agroszer at gmail.com
Thu Oct 9 05:53:51 EDT 2008
Log message for revision 91918:
major refactor between form.object and form.browser.object
also seem to got the where to pass object as value
Changed:
U z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.py
U z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.txt
U z3c.form/branches/adamg-objectwidget/src/z3c/form/field.py
U z3c.form/branches/adamg-objectwidget/src/z3c/form/object.py
-=-
Modified: z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.py
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.py 2008-10-09 08:42:21 UTC (rev 91917)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.py 2008-10-09 09:53:49 UTC (rev 91918)
@@ -1,3 +1,21 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""ObjectWidget browser related classes
+
+$Id$
+"""
+
__docformat__ = "reStructuredText"
import zope.component
import zope.interface
@@ -3,60 +21,13 @@
import zope.schema.interfaces
-from z3c.form import form, interfaces
-from z3c.form.widget import Widget, FieldWidget
+from z3c.form import interfaces, object
+from z3c.form.widget import FieldWidget
from z3c.form.browser import widget
-from z3c.form.error import MultipleErrors
-from z3c.form.object import ObjectSubForm
+class ObjectWidget(widget.HTMLFormElement, object.ObjectWidget):
+ zope.interface.implements(interfaces.IObjectWidget)
-class ObjectWidget(widget.HTMLFormElement, Widget):
- zope.interface.implementsOnly(interfaces.IObjectWidget)
-
klass = u'object-widget'
- subform = None
- _value = interfaces.NOVALUE
- def updateWidgets(self):
- if self._value is not interfaces.NOVALUE:
- self.subform = ObjectSubForm(self._value, self)
- ignore = None
- else:
- self.subform = ObjectSubForm(None, self)
- ignore = True
-
- self.subform.update(ignore)
-
- def update(self):
- super(ObjectWidget, self).update()
- self.updateWidgets()
-
- @apply
- def value():
- """This invokes updateWidgets on any value change e.g. update/extract."""
- def get(self):
- return self.extract()
- def set(self, value):
- if isinstance(value, tuple):
- try:
- value = interfaces.IDataConverter(self).toFieldValue(value)
- self._value = value
- except (zope.schema.ValidationError,
- ValueError, MultipleErrors), error:
- pass
- else:
- self._value = value
-
- # ensure that we apply our new values to the widgets
- self.updateWidgets()
- return property(get, set)
-
- def extract(self, default=interfaces.NOVALUE):
- if self.name+'-empty-marker' in self.request:
- self.updateWidgets()
- rv=self.subform.extractData()
- return rv
- else:
- return default
-
@zope.component.adapter(zope.schema.interfaces.IObject, interfaces.IFormLayer)
@zope.interface.implementer(interfaces.IFieldWidget)
Modified: z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.txt
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.txt 2008-10-09 08:42:21 UTC (rev 91917)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.txt 2008-10-09 09:53:49 UTC (rev 91918)
@@ -140,6 +140,7 @@
>>> v = MySubObject()
>>> v.foofield = 42
>>> v.barfield = 666
+ >>> v.__marker__ = "ThisMustStayTheSame"
>>> widget.ignoreContext = False
@@ -179,10 +180,16 @@
</body>
</html>
+The widget's value is NOVALUE until it gets a request:
+
+ >>> widget.value
+ <NOVALUE>
+
Let's fill in some values via the request:
>>> widget.request = TestRequest(form={'subobject.widgets.foofield':u'2',
- ... 'subobject.widgets.barfield':u'999'})
+ ... 'subobject.widgets.barfield':u'999',
+ ... 'subobject-empty-marker':u'1'})
>>> widget.update()
>>> print widget.render()
<html>
@@ -216,13 +223,27 @@
</body>
</html>
+ >>> v = widget.value
+ >>> v
+ <z3c.form.testing.MySubObject object at ...>
+ >>> v.foofield
+ 2
+ >>> v.barfield
+ 999
+The marker must stay (we have to modify the same object):
+ >>> v.__marker__
+ 'ThisMustStayTheSame'
+
+
+
Error handling is next. Let's use the value "bad" (an invalid integer literal)
as input for our internal (sub) widget.
>>> widget.request = TestRequest(form={'subobject.widgets.foofield':u'2',
- ... 'subobject.widgets.barfield':u'bad'})
+ ... 'subobject.widgets.barfield':u'bad',
+ ... 'subobject-empty-marker':u'1'})
>>> widget.update()
@@ -261,11 +282,13 @@
</body>
</html>
+ >>> widget.value
+ Traceback (most recent call last):
+ ...
+ MultipleErrors
-
-
In forms
========
@@ -300,9 +323,6 @@
>>> request = TestRequest()
>>> myaddform = MyAddForm(root, request)
-#>>> from pub.dbgpclient import brk; brk('192.168.32.1')
-
-
>>> myaddform.update()
As usual, the form contains a widget manager with the expected widget
@@ -492,9 +512,6 @@
99
>>> editform.request = request
-
-#>>> from pub.dbgpclient import brk; brk('192.168.32.1')
-
>>> editform.update()
Until we have updated the form:
@@ -806,3 +823,139 @@
</form>
</body>
</html>
+
+
+
+
+
+
+
+
+
+
+#Object in an Object situation
+#=============================
+#
+#
+#We define an interface containing a subobject, and an addform for it:
+#
+# >>> from z3c.form import form, field
+# >>> from z3c.form.testing import MyComplexObject, IMyComplexObject
+#
+#Note, that creating an object will print some information about it:
+#
+# >>> class MyAddForm(form.AddForm):
+# ... fields = field.Fields(IMyComplexObject)
+# ... def create(self, data):
+# ... print "MyAddForm.create", str(data)
+# ... return MyObject(**data)
+# ... def add(self, obj):
+# ... self.context[obj.name] = obj
+# ... def nextURL(self):
+# ... pass
+#
+#We create the form and try to update it:
+#
+# >>> request = TestRequest()
+#
+##>>> from pub.dbgpclient import brk; brk('192.168.32.1')
+#
+# >>> myaddform = MyAddForm(root, request)
+#
+##>>> from pub.dbgpclient import brk; brk('192.168.32.1')
+#
+#
+# >>> myaddform.update()
+#
+#As usual, the form contains a widget manager with the expected widget
+#
+# >>> myaddform.widgets.keys()
+# ['subobject', 'name']
+# >>> myaddform.widgets.values()
+# [<ObjectWidget 'form.widgets.subobject'>, <TextWidget 'form.widgets.name'>]
+#
+#The addform has our ObjectWidget which in turn contains a subform:
+#
+# >>> myaddform.widgets['subobject'].subform
+# <z3c.form.object.ObjectSubForm object at ...>
+#
+#Which in turn contains the sub-widgets:
+#
+# >>> myaddform.widgets['subobject'].subform.widgets.keys()
+# ['subfield', 'moofield']
+#
+# >>> myaddform.widgets['subobject'].subform.widgets['subfield'].subform.widgets.keys()
+# ['foofield', 'barfield']
+#
+#If we want to render the addform, we must give it a template:
+#
+# >>> addTemplate(myaddform)
+#
+#Now rendering the addform renders the subform as well:
+#
+# >>> print myaddform.render()
+# <html xmlns="http://www.w3.org/1999/xhtml">
+# <body>
+# <form action=".">
+# <div class="row">
+# <label for="form-widgets-subobject">my object</label>
+# <div class="object-widget required">
+# <div class="label">
+# <label for="form-widgets-subobject-widgets-subfield">
+# <span>Second-subobject</span>
+# <span class="required">*</span>
+# </label>
+# </div>
+# <div class="widget">
+# <div class="object-widget required">
+# <div class="label">
+# <label for="form-widgets-subobject-widgets-subfield-widgets-foofield">
+# <span>My foo field</span>
+# <span class="required">*</span>
+# </label>
+# </div>
+# <div class="widget">
+# <input class="text-widget required int-field"
+# id="form-widgets-subobject-widgets-subfield-widgets-foofield"
+# name="form.widgets.subobject.widgets.subfield.widgets.foofield"
+# type="text" value="1,111">
+# </div>
+# <div class="label">
+# <label for="form-widgets-subobject-widgets-subfield-widgets-barfield">
+# <span>My dear bar</span>
+# </label>
+# </div>
+# <div class="widget">
+# <input class="text-widget int-field"
+# id="form-widgets-subobject-widgets-subfield-widgets-barfield"
+# name="form.widgets.subobject.widgets.subfield.widgets.barfield"
+# type="text" value="2,222">
+# </div>
+# <input name="form.widgets.subobject.widgets.subfield-empty-marker" type="hidden" value="1">
+# </div>
+# </div>
+# <div class="label">
+# <label for="form-widgets-subobject-widgets-moofield">
+# <span>Something</span>
+# <span class="required">*</span>
+# </label>
+# </div>
+# <div class="widget">
+# <input class="text-widget required textline-field"
+# id="form-widgets-subobject-widgets-moofield"
+# name="form.widgets.subobject.widgets.moofield" type="text" value="">
+# </div>
+# <input name="form.widgets.subobject-empty-marker" type="hidden" value="1">
+# </div>
+# </div>
+# <div class="row">
+# <label for="form-widgets-name">name</label>
+# <input class="text-widget required textline-field"
+# id="form-widgets-name" name="form.widgets.name" type="text" value="">
+# </div>
+# <div class="action">
+# <input class="submit-widget button-field" id="form-buttons-add" name="form.buttons.add" type="submit" value="Add">
+# </div>
+# </form>
+# </body>
+# </html>
Modified: z3c.form/branches/adamg-objectwidget/src/z3c/form/field.py
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/field.py 2008-10-09 08:42:21 UTC (rev 91917)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/field.py 2008-10-09 09:53:49 UTC (rev 91918)
@@ -21,7 +21,7 @@
import zope.location
import zope.schema.interfaces
-from z3c.form import interfaces, util
+from z3c.form import interfaces, util, error
from z3c.form.error import MultipleErrors
from z3c.form.widget import AfterWidgetUpdateEvent
@@ -272,9 +272,9 @@
for name, widget in self.items():
if widget.mode == interfaces.DISPLAY_MODE:
continue
- raw = widget.extract()
value = widget.field.missing_value
try:
+ raw = widget.extract()
if raw is not interfaces.NOVALUE:
value = interfaces.IDataConverter(widget).toFieldValue(raw)
zope.component.getMultiAdapter(
Modified: z3c.form/branches/adamg-objectwidget/src/z3c/form/object.py
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/object.py 2008-10-09 08:42:21 UTC (rev 91917)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/object.py 2008-10-09 09:53:49 UTC (rev 91918)
@@ -23,7 +23,7 @@
from z3c.form.converter import BaseDataConverter
-from z3c.form import form, interfaces, util
+from z3c.form import form, interfaces, util, widget
from z3c.form.field import Fields
from z3c.form.error import MultipleErrors
from z3c.form.i18n import MessageFactory as _
@@ -84,69 +84,122 @@
self._validate()
-
class ObjectConverter(BaseDataConverter):
"""Data converter for IObjectWidget."""
zope.component.adapts(
zope.schema.interfaces.IObject, interfaces.IObjectWidget)
- factory = None
-
- def _fields(self):
- return zope.schema.getFields(self.field.schema)
-
def toWidgetValue(self, value):
"""Just dispatch it."""
if value is self.field.missing_value:
- return None
+ return interfaces.NOVALUE
return value
+ def toFieldValue(self, value):
+ """See interfaces.IDataConverter"""
+ if value is interfaces.NOVALUE:
+ return self.field.missing_value
+
+ return value
+
+
+class ObjectWidget(widget.Widget):
+ zope.interface.implements(interfaces.IObjectWidget)
+
+ subform = None
+ _value = interfaces.NOVALUE
+ _updating = False
+
+ def updateWidgets(self):
+ if self._value is not interfaces.NOVALUE:
+ self.subform = ObjectSubForm(self._value, self)
+ ignore = None
+ else:
+ self.subform = ObjectSubForm(None, self)
+ ignore = True
+
+ self.subform.update(ignore)
+
+ def update(self):
+ #very-very-nasty: skip raising exceptions in extract while we're updating
+ self._updating = True
+ try:
+ super(ObjectWidget, self).update()
+ self.updateWidgets()
+ finally:
+ self._updating = False
+
+ @apply
+ def value():
+ """This invokes updateWidgets on any value change e.g. update/extract."""
+ def get(self):
+ return self.extract()
+ def set(self, value):
+ if isinstance(value, tuple):
+ try:
+ value = interfaces.IDataConverter(self).toFieldValue(value)
+ self._value = value
+ except (zope.schema.ValidationError,
+ ValueError, MultipleErrors), error:
+ pass
+ else:
+ self._value = value
+
+ # ensure that we apply our new values to the widgets
+ self.updateWidgets()
+ return property(get, set)
+
def createObject(self, value):
#keep value passed, maybe some subclasses want it
#nasty: value here is the raw extracted from the widget's subform
#in the form of (value-dict, (error1, error2))
- if self.factory is None:
- name = self.field.schema.__module__+'.'+self.field.schema.__name__
- creator = zope.component.queryMultiAdapter(
- (self.widget.context, self.widget.request,
- self.widget.form, self.widget),
- interfaces.IObjectFactory,
- name=name)
- if creator:
- obj = creator(value)
- else:
- raise ValueError("No IObjectFactory adapter registered for %s" %
- name)
+ name = self.field.schema.__module__+'.'+self.field.schema.__name__
+ creator = zope.component.queryMultiAdapter(
+ (self.context, self.request,
+ self.form, self),
+ interfaces.IObjectFactory,
+ name=name)
+ if creator:
+ obj = creator(value)
else:
- #this is creepy, do we need this?
- #there seems to be no way to dispatch???
- obj = self.factory()
+ raise ValueError("No IObjectFactory adapter registered for %s" %
+ name)
return obj
- def toFieldValue(self, value):
- """See interfaces.IDataConverter"""
- if value is interfaces.NOVALUE:
- return self.field.missing_value
+ def extract(self, default=interfaces.NOVALUE):
+ if self.name+'-empty-marker' in self.request:
+ self.updateWidgets()
- if value[1]:
- raise MultipleErrors(value[1])
+ value = self.subform.extractData()
+ #value here is (data-dict, (error1, error2))
- if (self.widget._value is not interfaces.NOVALUE
- and not self.widget.subform.ignoreContext):
- obj = self.widget._value
- else:
- obj = self.createObject(value)
+ if value[1]:
+ #very-very-nasty: skip raising exceptions in extract while we're updating
+ if self._updating:
+ return default
+ raise MultipleErrors(value[1])
- obj = self.field.schema(obj)
+ if (self._value is not interfaces.NOVALUE
+ and not self.subform.ignoreContext):
+ obj = self._value
+ else:
+ obj = self.createObject(value)
- for name, f in self._fields().items():
- setattr(obj, name, value[0][name])
- return obj
+ obj = self.field.schema(obj)
+ for name in zope.schema.getFieldNames(self.field.schema):
+ try:
+ setattr(obj, name, value[0][name])
+ except KeyError:
+ pass
+ return obj
+ else:
+ return default
+
class FactoryAdapter(object):
"""Most basic-default factory adapter"""
More information about the Checkins
mailing list