[TurboGears] Re: Forms declarative style
On 11/16/05, Ian Bicking [EMAIL PROTECTED] wrote: Basically this: class MyForm(TableForm): foo1 = TextField() foo2 = TextField() Is exactly equivalent to: MyForm = type(TableForm)('MyForm', (TableForm,), {'foo1': TextField(), 'foo2': TextField}) this is probably a little too wacky, it turns out. Consider this case: class TableForm(Subclassable): def important_behavior(self): print foo TableForm = TableForm() class MyForm(TableForm): def important_behavior(self): print bar type(MyForm) - TableForm MyForm.important_behavior() - TypeError (takes 1 argument, 0 given) Not being able to override behavior would be an evil side effect of it looking like a class but not actually being a class. There's probably a way to bind the function to the instance, is there not? Kevin
[TurboGears] Re: Forms declarative style
Yeah, I've seen those. The order is only a problem because Python gives us the dict... Using the somewhat hacky counter technique plus an ordered dict may do the trick. Kevin On 11/17/05, Sean Cazzell [EMAIL PROTECTED] wrote: Kevin, The Python Cookbook has a couple of ordered dict implementations. Here's one: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/438823 Sean Cazzell On Thu, 2005-11-17 at 11:06 -0500, Kevin Dangoor wrote: On 11/16/05, [EMAIL PROTECTED] [EMAIL PROTECTED] wrote: 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. Being able to access in order or as a dictionary is a nice thing. I'll have to keep that in mind. Kevin -- Kevin Dangoor Author of the Zesty News RSS newsreader email: [EMAIL PROTECTED] company: http://www.BlazingThings.com blog: http://www.BlueSkyOnMars.com -- Kevin Dangoor Author of the Zesty News RSS newsreader email: [EMAIL PROTECTED] company: http://www.BlazingThings.com blog: http://www.BlueSkyOnMars.com
[TurboGears] Re: Forms declarative style
In my TG CRUD work, I generate edit form, view list and view screen from SQLObject. I use the similar approach of Kevin : using *arg or a list in the contrustor of a CompositeWidget. I also add an append() method. Advantages of this solution : * easy to create and extends a form automaticaly ... editWidgetMap = { 'container' : widget4edit.FormWidgetsList, 'default' : widget4edit.TextLineWidget, 'SOStringCol': widget4edit.TextLineWidget, 'SOStringCol+long': widget4edit.TextWidget, 'SOUnicodeCol': widget4edit.TextLineWidget, 'SOUnicodeCol+long': widget4edit.TextWidget, 'SOBoolCol': widget4edit.CheckBoxWidget, 'SOForeignKey' : widget4edit.VocabularyWidget, 'SOEnumCol' : widget4edit.VocabularyWidget, #'SOIntCol':IntWidget, #'SODateTimeCol':DateTimeWidget } 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
[TurboGears] Re: Forms declarative style
Kevin Dangoor wrote: On 11/16/05, Ian Bicking [EMAIL PROTECTED] wrote: Basically this: class MyForm(TableForm): foo1 = TextField() foo2 = TextField() Is exactly equivalent to: MyForm = type(TableForm)('MyForm', (TableForm,), {'foo1': TextField(), 'foo2': TextField}) this is probably a little too wacky, it turns out. Consider this case: class TableForm(Subclassable): def important_behavior(self): print foo TableForm = TableForm() class MyForm(TableForm): def important_behavior(self): print bar type(MyForm) - TableForm MyForm.important_behavior() - TypeError (takes 1 argument, 0 given) Not being able to override behavior would be an evil side effect of it looking like a class but not actually being a class. There's probably a way to bind the function to the instance, is there not? import new, types for attr, value in new_attrs.values(): if isinstance(value, types.FunctionType): setattr(self, attr, new.instancemethod(value, self, self.__class__) These are things that I think are worthy of exploration, but you have to be ready to back them out if they don't pan out. -- Ian Bicking / [EMAIL PROTECTED] / http://blog.ianbicking.org
[TurboGears] Re: Forms declarative style
Love to se something like that =) Cheers Ronald On Nov 18, 2005, at 6:55 AM, Michael Schneider wrote: Can take a STAN-like approach for building DOM fragments that we could pass to kid?? 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. Ronald Jaramillo mail: ronald AT checkandshare DOT com blog: http://www.checkandshare.com/blog
[TurboGears] Re: Forms declarative style
On 11/16/05, Ronald Jaramillo [EMAIL PROTECTED] wrote: Hi, The discussion yesterday about Form styles got me thinking. Personally I don't like the proposed declarative style. I like the idea that this style has the same feel as SQLObject (+1), though I don't buy the point about subclassing. As it is now, you can already subclass a form. Correct, you could subclass Form if you want customized behavior. But my main objection has something to do with consistency. If a form is a widget (and a widget container as well), why should they differ in style to other widget elements. Say we have a CheckboxGroup widget. Should it be used like this? niceDogs(CheckboxGroupBase): chiguagua = widgets.CheckBox() rodesian = widgets.CheckBox() pitbull = widgets.CheckBox(checked=true) I will rather see widgets as elements that can embed and be embeded as well. I think people were viewing forms as being different from individual widgets. Implementation-wise, right now, Forms are widgets and it functionally makes sense to have them that way. I was just thinking about the actual implementation of making forms support the declarative style and have two issues with the mechanics of it: 1) maintaining the order of the widgets 2) mechanics of actually using a Form As for #1, how does it work? widgetcounter = 0 class Widget(object): def __init__(...stuff...): global widgetcounter # acquire a lock self.widgetnum = widgetcounter widgetcounter += 1 # release lock class MetaForm(MetaWidget): def __init__(cls, name, bases, dct): super(MetaForm, cls).__init__(name, bases, dct) widgetlist = # get all of the widgets from dct.values() # sort them by widgetnum I believe that will work. But, yuck. As for the mechanics of using the form, what do people have in mind. As normal Widget instances, you use a form by doing form.insert(...) Would you still do MyForm.insert(...)? (So insert on a Form would have to be a classmethod, rather than an instance method?) 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... Kevin
[TurboGears] Re: Forms declarative style
On 11/16/05, Kevin Dangoor [EMAIL PROTECTED] wrote: So, it's like Ronald said: do you want Forms to be consistent withWidgets (and they *are* Widgets), or should they be consistent withSQLObject? The devil, as they say, is in the details... Personally, I favor a widget library that models known GUI idioms - that is, after all, what forms are - a GUI. The layout and handling of a GUI should be totally *indifferent* to what is handling the data. Maybe I'm reading too much into that last paragraph, but the implication is something unexpected. *sigh* I appologize if I'm speaking out of turn here, and plead ignorance. I haven't had time to look at the widget stuff, and have just barely touched forms at all. But I have looked through the source a little and it *appears* to be a nice way of programatically generating forms and retrieving data from them, which to me sounds like a web-baed GUI library, and that suggests to me that it would be a good idea to follow standard GUI idioms here and be as flexible as possible. That means, to me, that the library gives the programmer the means to lay things out, respond to events, and retrieve data as needed, but nothing beyond that ( i.e. the programmer should be the one stuffing it into a database, not the widget itself).And again, I appologize for making any statements out of ignorance on this subject. I'm REALLY behind the curve here. Hope this is helpful in some way. -- Things fall apart. The Center cannot hold.- Life as a QA geek, in a nutshell.Best,Jeff
[TurboGears] Re: Forms declarative style
On 11/16/05, Jeff Grimmett [EMAIL PROTECTED] wrote: On 11/16/05, Kevin Dangoor [EMAIL PROTECTED] wrote: 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... Personally, I favor a widget library that models known GUI idioms - that is, after all, what forms are - a GUI. The layout and handling of a GUI should be totally *indifferent* to what is handling the data. Maybe I'm reading too much into that last paragraph, but the implication is something unexpected. 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. But I have looked through the source a little and it *appears* to be a nice way of programatically generating forms and retrieving data from them, which to me sounds like a web-baed GUI library, and that suggests to me that it would be a good idea to follow standard GUI idioms here and be as flexible as possible. That means, to me, that the library gives the programmer the means to lay things out, respond to events, and retrieve data as needed, but nothing beyond that ( i.e. the programmer should be the one stuffing it into a database, not the widget itself). 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. Kevin
[TurboGears] Re: Forms declarative style
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. 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 defined in the class's dictionary, which is unordered, there's no way to determine the order they appear in the source code, so you have to use an array of fields instead. Maybe you could hack around it by using a @decorator that recorded the order it was applied to methods in another class variable. Oh, but those are fields not methods. You can't apply decorators to fields, but you could still call a function for every field that remembered its order. Eww, that's gross, never mind... -Don
[TurboGears] Re: Forms declarative style
Don Hopkins wrote: 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. 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 defined in the class's dictionary, which is unordered, there's no way to determine the order they appear in the source code, so you have to use an array of fields instead. If you control the source of TextField(), you can make it increment a counter everytime it is instantiated. Then you sort according to this counter, essentially sorting them by their creation time. This is how SQLObject started (if only recently) to keep track of the order of its columns. -- Ian Bicking / [EMAIL PROTECTED] / http://blog.ianbicking.org
[TurboGears] Re: Forms declarative style
Kevin Dangoor wrote: 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() I'd played around unsuccessfully with weird dual object/class objects, but I never quite figured it out. But I must know more now, because it wasn't too hard. Here's an example with a very brief test: http://svn.colorstudy.com/home/ianb/subclass_instance/ Basically this: class MyForm(TableForm): foo1 = TextField() foo2 = TextField() Is exactly equivalent to: MyForm = type(TableForm)('MyForm', (TableForm,), {'foo1': TextField(), 'foo2': TextField}) So if TableForm is an instance, then type(TableForm) is the class, and the class is called with those arguments (i.e., instantiating). It's all a little wacky, so I don't know that I'd recommend the trick. But it does make large keyword-based instanciation easier on the eye. -- Ian Bicking / [EMAIL PROTECTED] / http://blog.ianbicking.org
[TurboGears] Re: Forms declarative style
If you control the source of TextField(), you can make it increment a counter everytime it is instantiated. Then you sort according to this counter, essentially sorting them by their creation time. This is how SQLObject started (if only recently) to keep track of the order of its columns. Great point, bravo! I had wished there was a way to get the order of SQLObject fields, but I didn't realize you've already figured out a way to do it! There is nothing wrong with your television set. Do not attempt to adjust the picture. We are controlling the transmission. If we wish to make it louder, we will bring up the volume. If we wish to make it softer, we will tune it to a whisper. We will control the horizontal. We will control the vertical. We can roll the image; make it flutter. We can change the focus to a soft blur or sharpen it to crystal clarity. For the next hour, sit quietly and we will control all that you see and hear. We repeat: there is nothing wrong with your television set. You are about to participate in a great adventure. You are about to experience the awe and mystery which reaches from the inner mind to the Outer SQLObject. -Don
[TurboGears] Re: Forms declarative style
Don Hopkins wrote: 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 defined in the class's dictionary, which is unordered, there's no way to determine the order they appear in the source code, so you have to use an array of fields instead. Maybe you could hack around it by using a @decorator that recorded the order it was applied to methods in another class variable. Oh, but those are fields not methods. You can't apply decorators to fields, but you could still call a function for every field that remembered its order. Eww, that's gross, never mind... To me, the order in the class doesn't matter. What usually matter is when it is passed to the view in MVC which in TurboGear's case is a dict for Kid to consume. I just created a preferred ordered dict which has an optional field sequence list member. 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.
[TurboGears] Re: Forms declarative style
On 11/16/05, Kevin Dangoor [EMAIL PROTECTED] wrote: 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 consistentwith how other widgets (TextField, for example) work.Well, I can see the point of some folks in this case since it certainly jibes with typical GUI idioms I've used, at their simplest. 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. To me, that just seems like the right way to do it, but I'm fairly naive with regards to web apps.-- Things fall apart. The Center cannot hold.- Life as a QA geek, in a nutshell. Best,Jeff
[TurboGears] Re: Forms declarative style
On 11/16/05, Don Hopkins [EMAIL PROTECTED] wrote: The problem with the class based approach is that there's no way toreconstruct the order of the fields in the class, which is required forgenerating forms (of more than one field ;-). Since the fields are Beware of stupid question.Here it is.Why is it important to reconstruct the order of the fields?-- Things fall apart. The Center cannot hold.- Life as a QA geek, in a nutshell. Best,Jeff
[TurboGears] Re: Forms declarative style
Jeff Grimmett wrote: On 11/16/05, Don Hopkins [EMAIL PROTECTED] wrote: 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 Beware of stupid question. Here it is. Why is it important to reconstruct the order of the fields? presentation. But I don't think class level definition order is the solution(see my other post about this). 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.
[TurboGears] Re: Forms declarative style
Good question actually. Its 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 Ians invented a way to order the fields of an SQLObject, its 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 cant 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 dont 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 -Original Message- From: turbogears@googlegroups.com [mailto:[EMAIL PROTECTED] On Behalf Of Jeff Grimmett Sent: Wednesday, November 16, 2005 8:40 PM To: turbogears@googlegroups.com Subject: [TurboGears] Re: Forms declarative style On 11/16/05, Don Hopkins [EMAIL PROTECTED] wrote: 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 Beware of stupid question. Here it is. Why is it important to reconstruct the order of the fields? -- Things fall apart. The Center cannot hold. - Life as a QA geek, in a nutshell. Best, Jeff
[TurboGears] Re: Forms declarative style
Don Hopkins wrote: 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 is meant to hang data user off of it; I could add it to the other objects as well, and probably a __getattr__ as well. The reason they are specially collected is so that the values can also be transfered to the SO* version of the classes. -- Ian Bicking | [EMAIL PROTECTED] | http://blog.ianbicking.org