Controlling form/widgets output
Hi all -- I've started to poke around in customizing the generated form code and providing my own widget instances, but the current Django form code is written in such a way that it makes things nearly impossible. Here's just one example: when fields are written out to HTML, they get asked "what attributes does this kind of widget need?". Adding a widget therefore requires rewriting the field classes you want the widget to be used with, rather than letting the widget interrogate the field classes. That's not great design, and it means any changes to form rendering becomes a major pain. Is there any work being done to clean up the way Django creates forms? I saw there was something being done with DOCTYPE declarations, but it didn't look like that was making very extensive changes. -- Chris --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-developers@googlegroups.com To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-developers?hl=en -~--~~~~--~~--~--~---
Re: Controlling form/widgets output
On Jan 21, 5:37 pm, Russell Keith-Magee wrote: > > Here's just one example: when fields are written out to HTML, they > > get asked "what attributes does this kind of widget need?". > > Unless I'm misunderstanding your intent with this statement - No, they > aren't. A form contains fields, which describe the type of data that > is being collected and the validation procedures for said data. Each > field provides a widget, which describes a HTML element that allows > that data to be collected. When the form is rendered, it binds some > data to a field instance in a BoundField, and renders the BoundField > using the widget for the field. Well, it seems to me that makes for an *extremely* tight coupling between the model and the view. And it's a little difficult for me to understand what value there is in such a tight coupling--if I've got a DateField, why can't I have it represented in an HTML page by a javascript calendar pop-up, or a text box, or three select boxes (month, day, and year). Plus, any time you collect a password you need to display it in a form using a password input, not the stock text input. And I might very well have two separate form fields which should be displayed as a single unit. There's a need to have the display decoupled from the form logic. Django just doesn't provide much help in doing that. > The field isn't asked anything > during the rendering process beyond "what is your widget?". Not true. There's a "widget_attrs" method on the base Field class which passes a widget and expects to be passed back a dictionary of attributes to be added to the widget. In other words, if I create a widget which renders a CharField and I'd like to validate the maximum length, I either *must* inherit from TextInput or PasswordInput, edit the CharField class, or write a different CharField class that's aware of my new widget. > > Is there any work being done to clean up the way Django creates > > forms? I saw there was something being done with DOCTYPE > > declarations, but it didn't look like that was making very extensive > > changes. > > In short, no. We completed a major refactor of the forms framework > just before v1.0 landed, and we're not really looking to make another > major change. > > However - our commitment is to backwards compatibility, not to no > change at all. If you have a specific problem that can't be solved, > feel free to make a specific suggestion on how to improve things. If I were writing it, I'd make the Form class responsible for defining the order of the fields, the labels, the validation logic and errors. The Fields would be part of that. I'd make a FormRenderer class which was responsible for drawing a form in different formats (as a list, as a table, etc ...) and Widgets would act as a bridge between a Field (or group of fields) and the FormRenderer. -- Chris --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-developers@googlegroups.com To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-developers?hl=en -~--~~~~--~~--~--~---
Re: Controlling form/widgets output
On Jan 21, 7:20 pm, Malcolm Tredinnick wrote: > In the larger scheme, I think this is one of those areas where people's > initial intuition differs. Django's form classes generally push > downwards, with the greater intelligence lying at the higher levels > (forms know the most, then form field classes have more localised > knowledge and the widgets have the least knowledge and are simply given > the information that they should present). Well, I can see that; it just seems to me that a form (and fields) should be responsible for managing data on the server side, while a widget is responsible for managing data on the client side. It has to be, since the Fields aren't running there. > Again, specific issues would be easier to address here, rather than > general complaints. We have a lot of accumulated experience to suggest > the current design isn't a total disaster and I'm yet to find anything > that isn't possible in a fairly neat fashion with the current dependency > direction. So what sort of things are you trying to do where you can't > think of a way to implement them at the moment? I'm trying to replace some of form elements on my site with Dojo widgets. In some cases I can handle it by just modifying attributes. But my foray into all this began because I needed to have the widgets being rendered in a form aware of some properties set on the form itself--so I could say something like "if you're rendering an INPUT element, add a 'class=form-input' attribute to the rendered html". I initially assumed I could just subclass Form, and add my custom Widget parameter to each Field. Then my Form could check when rendering a Widget whether it was a custom widget or not, and call a special rendering method if it was. But the Form rendering logic doesn't make that easy at all. I ended first iterating over all the fields in the form and calling a method which tells it what to do when it gets rendered, every time it gets rendered. Then I call the normal rendering functions, which work as expected. But I'm not very happy with that, since it relies quite a lot on some of the internal details of how Forms work. -- Chris --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-developers@googlegroups.com To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-developers?hl=en -~--~~~~--~~--~--~---
Re: Controlling form/widgets output
On Jan 22, 12:12 am, Jacob Kaplan-Moss wrote: > On Thu, Jan 22, 2009 at 4:57 PM, catsclaw wrote: > > Well, it seems to me that makes for an *extremely* tight coupling > > between the model and the view. > > I'm sorry to be so blunt, but your perception is misguided. Forms have > no dependancy upon models, nor do models on forms, nor must views use > forms, models, or anything, really. I could have been clearer. I'm not talking about Django Models here; I'm talking about models, views, and controllers from the Model- View-Controller design pattern. Django widgets would correspond to views, while Django forms would correspond to models. In the current architecture, this division is very muddled; I suggested reducing the interdependency and adding a FormRenderer class; that would allow the display elements (widgets) to be handled by a display controller (a form renderer) while the model elements (fields) were handled by a model controller (the form). > > And it's a little difficult for me to > > understand what value there is in such a tight coupling--if I've got a > > DateField, why can't I have it represented in an HTML page by a > > javascript calendar pop-up, or a text box, or three select boxes > > (month, day, and year). > > It's difficult to understand because you've assumed it's impossible; > it's not. A quick google search for "django datefield select" ... No, no. You're missing my point. I was responding to Russell, who said "A form contains fields ... Each field provides a widget, which describes a HTML element that allows that data to be collected." That description--that forms contain many fields, and each field corresponds to a widget--isn't sufficient to explain the relationship between forms, fields, and widgets. And it's a very limiting conception of what the form functionality ought to do for Django as well. > > Plus, any time you collect a password you need to display it in a > > form using a password input, not the stock text input. > > Again, this is in fact not only possible, but easy:: > > class MyForm(forms.Form): > password = forms.CharField(widget=forms.PasswordInput) Yes, I know this. That's why I used it as an example. This is a case where the field gets asked, during the rendering process, "I'm drawing a PasswordInput, are there any extra attributes I should add?" and the field adds the input length to the HTML. I'm rather aghast that Fields are expected to know about HTML at all, let alone be aware of all the available widgets so they can modify them. A better design is to have the fields open to interrogation by widgets. That way, a widget can ask if there's a limit on the number of characters in this field. That way new widgets and new fields work together, without having to know about each other ahead of time. > Why don't we start over here: what is the problem? What did you try do > do? What did you expect to happen? What actually happened? Very well. I'm trying to write a subclass of Form that knows about Dojo forms, and will render them appropriately. To do this, I assumed I would subclass Form (as DojoForm) and then create a widget for each Dojo form element I wanted to use. The DojoForm would have a number of settings relating to the form as a whole, which would alter the way each DojoWidget rendered itself. When a DojoForm gets passed to a template, I could then call a method in the head of the document that would know what statements to place in the Javascript, and a different method in the body of the document which would render the actual form proper. What's the best way of doing this? -- Chris --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-developers@googlegroups.com To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-developers?hl=en -~--~~~~--~~--~--~---
Re: Controlling form/widgets output
On Jan 22, 12:12 am, Jacob Kaplan-Moss wrote: > Why don't we start over here: what is the problem? What did you try do > do? What did you expect to happen? What actually happened? Here's another problem I'm stuck at. I'm trying to determine, within a widget, whether I'm being asked to draw a field that is required, so I can add JavaScript validation on the form submit. Is this possible? -- Chris --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-developers@googlegroups.com To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-developers?hl=en -~--~~~~--~~--~--~---
Re: Controlling form/widgets output
On Jan 22, 11:53 pm, Russell Keith-Magee wrote: > On Fri, Jan 23, 2009 at 5:02 AM, catsclaw wrote: > > I could have been clearer. I'm not talking about Django Models > > here; I'm talking about models, views, and controllers from the Model- > > View-Controller design pattern. Django widgets would correspond to > > views, while Django forms would correspond to models. In the current > > architecture, this division is very muddled; I suggested reducing the > > interdependency and adding a FormRenderer class; that would allow the > > display elements (widgets) to be handled by a display controller (a > > form renderer) while the model elements (fields) were handled by a > > model controller (the form). > > Again, either I've misunderstood you, or you don't understand how MVC > works. Your usage of terms like "model controller" and "display > controller" certainly serve to confuse matters nicely. Yeah, I shouldn't talk in shorthand. And my conception of how this probably ought to work, in a perfect universe, is not only evolving as I talk about it, but is kind of secondary to the point I'm trying to make, which is that Django's form classes don't separate the roles cleanly. My understanding of MVC is colored from my work with Java, which used a modified version for their UI framework. There, the View and Controller are coupled, but divorced from the Model. > The Form (model) holds a block of form data. > > The Widget (view) describes how to render form elements. > > The Field (controller) provides a way to extract data from the user > interface (i.e., process raw blocks of text from a HTTP POST) and > convert them into data suitable for storage in the model. But it doesn't work like that in practice. The Form contains raw HTML in its implementation (in the as_p method, for example) and contains hardcoded links (through the BoundField class) to widgets to use for a TextInput or Textarea. A Field contains rules for validating itself, while the Form has rules (although not many in the base class) for validating groups of fields. Fields also contain HTML to inject into widgets. > > And it's > > a very limiting conception of what the form functionality ought to do > > for Django as well. > > I fail to see why - but this might be a matter of misunderstanding of > scope. Django's forms framework makes claims as a HTTP data > manipulation tool with some minor sideline capabilities as a HTML > layout tool. For any non-trivial, post-prototype application, I would > expect the web designer to have much more control over form layout > than Django's basic form renderer. Sure, but that's the point. If I had a trivial application, I wouldn't *need* a framework to help. The web designer should have control over form layout. But as it is, I can't very easily provide that as a programmer. And saying "draw this field over here" through {{ form.field_name }} doesn't let me muddle about with the attributes set on that field as a web designer. > Coming up with perfect automated and customizable form layout has not > historically been a core concern of Django - simply because it is > impossible to well in an automated way. As a result, there hasn't been > much focus placed on layout of _forms_. > > If this is the feature you're looking for (and it sounds like it might > be) then sure - there is room for improvement. However - again - this > could be accommodated without a wholesale teardown of the forms > framework. What you're calling for is a refactor of > Form._html_output() to allow for easier customization of form output. I never called for a wholesale teardown of the forms framework. All I asked was "Is there any work being done to clean up the way Django creates forms?" In all the digging around I've done, I'd make the following suggestions: 1) Define some "standard" attributes for fields (like "max_length", "max_value", "required") and document them. Similarly, document the python type each field stores its value internally as, and what types its clean() method will accept. Maybe this exists somewhere, but I've been looking directly at the code, and it's not there. 2) Delete (or heavily deprecate) the Field.widget_attrs method. Widgets are expected to interrogate their associated Fields for this information. 3) Refactor the Form class into a Form class and a FormRenderer class. The FormRenderer takes a Form and provides an HTML layout. The Form doesn't know any HTML, but is otherwise responsible for everything it currently is. 4) Change widgets (or, for backward compatibility, add an "advanced" rende