So, it's like Ronald said: do you want Forms to be consistent with
Widgets (and they *are* Widgets), or should they be consistent with
SQLObject? The devil, as they say, is in the details...
So for my CRUD requirement, I just use py:for in Kid and still control
the order of how those fields appears. And if I later decide to
customize the layout in Kid, the same dict can still be used for direct
name access.
Yep, you're reading too much into that last paragraph. What I meant was...
forms are currently declared like this:
myform = TableForm([TextField("foo1"), TextField("foo2")])
and SQLObjects are declared like this:
class MyTable(SQLObject):
foo1 = StringCol()
foo2 = StringCol()
Some folks have expressed that they'd like forms to be like this:
class MyForm(TableForm):
foo1 = TextField()
foo2 = TextField()
which is consistent with the SQLObject style, but is not consistent
with how other widgets (TextField, for example) work.
Yep. While some day someone may write a data-aware widget, the core, basic widgets know nothing and care nothing about what happens to the information once it gets into your controller method.
The problem with the class based approach is that there's no way to
reconstruct the order of the fields in the class, which is required for
generating forms (of more than one field ;-). Since the fields are
Take the current catwalk module.
It allows you to drag/drop columns for presentation purpose. However, a
refresh would wipe it. It would be nice these things can be changed
easily and stored.
Good question actually.
It’s user friendly to group related elements together in the form (like x and y coordinates), and put important ones near the top (like title and description), so you need some way to control the order of dynamically generated form elements (and also a way to further customize each element).
Now that Ian’s invented a way to order the fields of an SQLObject, it’s possible to automatically generate forms to edit their fields in the same order they were specified by the database designer (or declared in the python class).
I want to be able to declare not only the order, but also other metadata about each field.
I made a database browser for OpenLaszlo based on SQLObject, but I resorted to awkward kludgery to order the fields with sequence numbers.
http://www.donhopkins.com/drupal/node/44
Using an older version of SQLObject, I subclassed the various field and join classes so the constructors took an extra user defined “data” parameter that I could retrieve later.
So I could hang a dictionary off of each field, to give it a sequence number to sort by, and store other presentation related information.
I also had to subclass the various join fields so they had data parameters too.
The goal was to declare extra information about each field and join, like its sequence number, the name of a custom editor, user friendly label, help text, and other presentation parameters, so the server can automatically generate XML to drive a Laszlo user interface for browsing and editing the database, with custom widgets like checkboxes, image views, date pickers, map widgets, etc.
(BTW: I can’t wait till Google Base drops the other shoe and publishes a web API!)
The new version of SQLObject now has a similar but undocumented feature that I don’t quite understand, with the _extra_vars Field instance variable, so I may be able to clean up my code and use that, instead of wrapping everything with my own subclasses.
Ian, how did you intend _extra_vars to be used: is it meant to hang user data off of fields, or am I subverting its true goal in life (remaining secret and behind the scenes in an undisclosed location)?
The Join classes would also need to support _extra_vars as well.
It would be great for dynamic user interface generation, if SQLObject supported an easy, documented way to attach metadata to fields and joins, and officially exposed the field order too, please!
-Don
def buildWidgetsList(self, sqlobj, widgetmap):
"""
@param sqlobj the type (like app.model.Page) for wich create a
WidgetContainer
@param widgetmap the family of widgets to use for each
SQLObject field type
"""
back = []
columns = sqlobj.sqlmeta.columns
for col in sqlobj.sqlmeta.columnList:
name = col.origName
clazz = col.__class__.__name__
if (clazz == 'SOStringCol' or clazz == 'SOUnicodeCol') and
not(col.length):
clazz += '+long'
widget = widgetmap.get(clazz,
widgetmap['default'])(key=name)
if hasattr(widget, 'vocabulary') and (widget.vocabulary is
None):
if clazz == 'SOForeignKey':
referencedsql = findClass(col.foreignKey)
widget.vocabulary = SQLVocabulary(referencedsql)
elif clazz == 'SOEnumCol':
widget.vocabulary =
widgetsupport.Vocabulary(col.enumValues)
if hasattr(widget, 'defaultValue') and
(widget.defaultValue is None):
widget.defaultValue = col.enumValues[0]
if hasattr(widget, 'required') and (widget.required is
None):
widget.required = col.notNone
if hasattr(widget, 'validator') and (widget.validator is
None):
widget.validator = col.validator
back.append(widget)
return widgetmap['container'](*back) #IGNORE:W0142
...
* the WidgetContainer instance could be attach to a SQLObject type. In
my case after building a WidgetContainer I do :
if not(hasattr(sqlobj, 'editWidget')):
#autogeneration of the editwidget
sqlobj.editWidget = self.buildWidgetsList(sqlobj,
self.editWidgetMap)
sqlobj.editWidget.append(widget4edit.HiddenWidget('isNew',
validators.Bool(), True))
sqlobj.editWidget.append(widget4edit.HiddenWidget('id',
validators.Int(), -1))
* you could create 2 instances of the same WidgetContainer, an each one
could have it's own internal state without interference, like 2
instances of TextField... (may be my java background influence me too
much, but class state/field are share by all instance, and there is
only one class definition available in the system)
my 2 cents
I will try to work up an example.
Here is a nice over link of stan
http://www.kieranholland.com/prose/meet-stan/
Thanks
Mike
PS. Divmod uses formless to render forms, I have not used formless
yet, so I have not input on that system.
You can also disable output encoding in kid for some html tags .
from kid import serialization
serialization.HTMLSerializer.noescape_elements.add('div')
Then in your template you dont need to use XML() .
<div py:content="test"/>
It would be nice to have something like disable-output-encoding in xsl
(disabling output encoding localy and not for all html tags you define)
:
<div py:content="test" disable-output-encoding="yes"/>