On Sep 12, 2006, at 2:35 PM, Adrian Holovaty wrote:
> I've put together the beginnings of the manipulator framework
> replacement, using ideas from the various proposals we've had, plus
> inspiration from some prior art (the previous Django form/manipulator
> system, plus some ideas from FormEncode).
Yay!
Generally, this rocks. My questions follow...
> As an alternative, my proposal has two main classes: Form and
> BoundForm. A Form is similar to an old Manipulator -- it's a
> collection of validation fields and encapsulates the concepts of form
> display, validation and redisplay. A BoundForm is simply a Form plus
> data. Thus, a BoundForm knows how many validation errors it has, knows
> how to display itself with the given data populated in the form, and
> can return a single field's errors and display. This is similar to the
> old FormWrapper class, but simpler and cleaner.
Out of curiosity, did you consider having a single ``Form`` object
that may be bound or unbound? It seems like most of ``BoundForm``
simply delegates down to the enclosed ``Form``, so perhaps ``Form.bind
()`` should store the data internally and just behave differently
once bound?
This would likely result in code within ``Form`` like::
if self.is_bound():
# whatever
I don't think I have a strong feeling either way... it seems it might
be slightly easier to only have to deal with a single object instead
of ``Form``/``BoundForm``, but perhaps you've already thought about
that.
> Hence, with this new API, the above view code would be written like
> this:
>
> form = ContactForm()
> if request.method == 'POST' and form.is_valid(**request.POST):
> send_email_and_redirect()
> return render_to_response('email_form.html', {'form':
> form.bind(**request.POST)})
Beautiful.
> The template would look like this:
I'd very much like to see ``{{ form }}`` simply spit out some (nice,
semantically-correct) default HTML so that the common case of using
forms is as easy as possible. Given good enough HTML, we should be
able to make form display a bit simpler.
This probably means giving form fields (optional) "human-readable"
names, but that's a good addition as far as I'm concerned.
> 1. form.sendername.errors.as_url rather than
> form.sendername.html_error_list. This gives us some flexibility to add
> other error shortcut-display types, like JavaScript or something.
>
> 2. "form.sendername.as_text" rather than "form.sendername". I'm not
> 100% sold on this idea, but I've been toying with the idea of
> controlling the decision of the HTML widget *in the template* like
> this. The implication of this is that the field definitions (when you
> define your Form class) are purely data-oriented, rather than
> presentation-oriented. Maybe each form field type can have a default
> HTML display, to save on typing "as_text". Also, there would need to
> be a way of specifying custom HTML attributes for those widgets -- the
> as_text() and as_textarea() methods take an "attrs" parameter, but
> we'd also have to be able to specify the attributes in the template
> somehow. Maybe we could provide a template tag that does this.
For simplicity, I'd *really* like these to be spelled ``
{{ form.sendername.errors }}`` and ``{{ form.sendername }}``.
Rendering a form/errors as some default HTML is the common case;
doing something more complex is less common.
I like the idea of having ``{{ form.sendername.as_textarea }}`` as an
option (along with ``{{ form.sendername.errors.as_javascript }}`` [or
whatever]), but I really think we should keep the common case as
simple as possible.
> class ContactForm(Form):
> sendername = TextField()
> senderemail = EmailField()
> subject = TextField(maxlength=20, blank=True)
> message = TextField()
Love it. I assume these fields live within ``django.forms``, yes?
> Another thing to note: In the current Manipulator framework, sometimes
> it is convenient to be able to construct self.fields dynamically. We
> should provide a way to do that with the new syntax.
Indeed; assuming ``self.fields`` is writable, it seems that
``__init__`` is the natural place to do this, still. So::
class ContactForm(Form):
sendername = TextField()
senderemail = EmailField()
subject = TextField(maxlength=20, blank=True)
message = TextField()
def __init__(self, use_second_message):
if use_second_message:
self.fields.append(TextField(name="second_message"))
?
> Finally, how does this stuff tie into models? Well, it's completely
> decoupled from models, but we should have some helper functions that
> create a Form from a model. (This is equivalent to the automatic
> AddManipulator and ChangeManipulator classes we already create for
> each model.) But the added flexibility of this new system will let us
> do things like specify a special-case Form that an admin page uses,
> and make it easy to create a Form that is based *almost* entirely on a
> model but, say, removes a few fields.
I'd say a ``Form`` class method is the right way to go::
form = Form.edit_form(Person.objects.get(pk=3))
form = Form.create_form(Person)
?
Again, rock on -- this is very cool!
Jacob
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Django developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/django-developers
-~----------~----~----~----~------~----~------~--~---