#22719: Proposal: Delayed Form binding (with working example code)
------------------------------------+--------------------------------
     Reporter:  bernhard.hermann@…  |      Owner:  nobody
         Type:  New feature         |     Status:  new
    Component:  Forms               |    Version:  1.6
     Severity:  Normal              |   Keywords:  bound unbound bind
 Triage Stage:  Unreviewed          |  Has patch:  0
Easy pickings:  0                   |      UI/UX:  0
------------------------------------+--------------------------------
 Hello everybody!

 I would like to propose adding a mechanism to "bind" Form-objects in a way
 other than at instantiation (e.g. {{{ Form(request.POST)}}}).

 This idea was inspired by the following assertion by Paul Graham:
   "When I see patterns in my programs, I consider it a sign of trouble.
   The shape of a program should reflect only the problem it needs to
   solve. Any other regularity in the code is a sign, to me at least,
   that I'm using abstractions that aren't powerful enough-- often that
   I'm generating by hand the expansions of some macro that I need to
   write."   [ http://www.paulgraham.com/icad.html ]

 Let me give a quick example from the Django documentation's "Working with
 forms":
 {{{#!python
 def contact(request):
     if request.method == 'POST':
         form = ContactForm(request.POST)
         if form.is_valid():
             pass
         else:
             form = ContactForm()

     return render(request, 'contact.html', {'form': form,})
 }}}
 [ highlighted: http://pastebin.com/MAKUSrmY ]

 This works well when I don't need to supply any keyword arguments. As soon
 as I want to do that, the code looks like this:
 {{{#!python
 def contact(request):
     if request.method == 'POST':
         form = ContactForm(request.POST, prefix='something-%s' %
 (some_id,), label_suffix=': ')
         if form.is_valid():
             pass
     else:
         form = ContactForm(prefix='something-%s' % (some_id,),
 label_suffix=': ')

     return render(request, 'contact.html', {'form': form,})
 }}}
 [ highlighted: http://pastebin.com/9FKS9ExU ]

 The really bad (IMHO: wrong) thing about this is that the code
 {{{    prefix='something-%s' % (some_id,), label_suffix=': '}}}
 must be duplicated.

 I am therefore using this class to bind the Form late:
 {{{#!python
 class FlexiForm(forms.Form):
     def set_fields(self):
         for (f_name, attributes) in self._thefields.items():
             for (att_name, att_value) in attributes.items():
                 setattr(self._theinstance.fields[f_name], att_name,
 att_value)

     def __init__(self, form, args=None, kwargs=None, fields=None):
         self._theform = form
         self._theargs = args or []
         self._thekwargs = kwargs or {}
         self._thefields = fields or {}
         self.bind()

     # !: make it possible to use kwargs here
     def bind(self, *args):
         self._theinstance = self._theform(*(list(args) + self._theargs),
 **self._thekwargs)
         self.set_fields()
         return self

     def __getattr__(self, name):
         return getattr(self._theinstance, name)

     def __setattr__(self, name, value):
         inst = self
         if name not in ['_theform', '_theargs', '_thekwargs',
 '_thefields', '_theinstance']:
             inst = self.__theinstance
         super(FlexiForm, inst).__setattr__(name, value)
 }}}
 [ highlighted: http://pastebin.com/wzY4qWUJ ]
 (This is the actual verbatim class from my code. If you spot any errors,
 please tell!)

 Melding this with the above example, we get:
 {{{#!python
 def contact(request):
     form = FlexiForm(ContactForm, kwargs={'prefix': 'something-%s' %
 (some_id,), 'label_suffix': ': ',})
     if request.method == 'POST':
         form.bind(request.POST)  # substitutes internal ContactForm() with
 ContactForm(request.POST)
         if form.is_valid():
            pass
     else:
         pass  # Form already instantiated!

     return render(request, 'contact.html', {
         'form': form,
     })
 }}}
 [ highlighted: http://pastebin.com/zNA9MzRJ ]

 '''Advantage: keyword (and other) arguments that are vitally important to
 many of my forms don't need to be duplicated in different locations.
 Probability of mistakes/bugs is lowered, maintainability and readability
 improved.'''

 I am sure there is a more elegant/correct way to do this.
 I suspect it should be added to Django's Form class.

 I am looking forward to your ...
 [x] criticism
 [x] reasons why this shouldn't be done
 [x] promises that it will be implemented soon
 [x] mindless ranting

 best regards,
 Bernhard

-- 
Ticket URL: <https://code.djangoproject.com/ticket/22719>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To post to this group, send email to django-updates@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/072.f13010e01998d3b9b093f5a7cf0bca26%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to