Introduction
Django newforms (see here: http://www.djangoproject.com/documentation/newforms/) are very nice, but they allow editing of plain single form, where fields specified as array.
field1 xxxxxxxxxxxxx
field2 xxxxxxx
field3 xxx-xxx-xxx
What if we want to edit data in table-like view, like in Excel? Where columns are fields from our database, and rows are records from table.
field1 | field2 | field 3
----------------------------
row1 xxxxxx xxxxxx xxxxx
row2 xxxxxx xxxxxx xxxxx
That is exact situation where this extension helps. It allows to specify fields, in newform style, for edition in Table. Form handling and everything else is very similar to one which Newforms library provides, making it easy to start for novice users without going into deep details.
Installation
As usually, to install this, just install DjHDGutils and place them in your PYTHONPATH.
Usage
All examples can be accessed via:
svn co http://public.halogen-dg.com/svn/repos/DjHDGutils/examples
Lets start from simplest possible model example
cd NewformsTableEdit ./manage.py syncdb
Adding some test data
./manage.py loaddata cars.json
Now, start writing a view for that data, in newforms-table manner. That is where the most interesting part starts. Since table view to data is a form by itself, we re-used newforms definitions for the fields, so we can use them right away:
class EditSalesPriceTable(TemplatedTable): id = forms.IntegerField(widget=forms.HiddenInput,required=False) name = forms.CharField() old_price = forms.DecimalField() new_price = forms.DecimalField()
As you see, the interface to define the form itself kept unchanged from standard Newforms. What is different, is that instead of editing single object, we are editing a few of them.
To render form, just put the variable in template, like this:
<form method="post">
{{ form_table }}
<input type="submit">
</form>
And it will render nicely, as typical form:
View for processing this form looks very similar to the typical Django form processing view. Example is here.
Validation works normally, for example, if we make one field empty and try 'submit', validation error will highlight the correct table cell:
Complex forms
In real life, forms are usually a lot more complicated. One would like to combine two approaches (typical horizontal Newforms layout) with vertical one (table-layout). In even more complicated examples, form would have a few AJAX sub-forms which will appear on mouse click. Is it possible to implement? And the answer is: Yes. Here is one of such forms which we developed in custom Sales Processing databases:
On this form, you see:
- 3 different AJAX enabled sections (marked with icons of pen and glass)
- Delivery Address form (appears in JS popup window)
- Billing address form (appears in popup)
- Type-in follow - product SLUG search by requesting slugs from server asynchronously
- Form itself combines from 2 forms - horizontal and vertical tables
- Vertical table can automatically expand to adding more products?
How this has been done? The answer is that that all is possible by using very simple trick: a field, which is called FormField, and contains form itself. So, form in example, looks as:
from DjHDGutils.newforms import TemplatedForm,TemplatedTable,FormField,RangeField ... class OrderForm(TemplatedForm): id = forms.IntegerField(widget=forms.HiddenInput,required=False) invoice_date = forms.DateField(label=u"Invoice date",input_formats=('%d/%m/%Y','%d-%m-%Y'),widget=DateWidget(format="%d/%m/%Y")) source = forms.IntegerField(label=u"Source",widget=forms.Select(choices=[(item.id,item.name) for item in G3Source.objects.all()])) ship_address = FormField(label=u"Delivery address",widget=FormWidget(subform=ShipAddressForm())) bill_address = FormField(label=u"Billing address",widget=FormWidget(subform=BillAddressForm(),buttons=bill_extra_button)) item_type = forms.ChoiceField(label=u"Delivery method",widget=forms.Select(attrs={'onchange':'on_product_type_change(this);'})) supplier = forms.ChoiceField(label=u"Supplier") apply_discount = forms.DecimalField(label=u"Discount, %",initial=Decimal('0.0')) cust_ref = forms.CharField(label=u"Customer reference",max_length=100,required=False) class OrderTable(TemplatedTable): id = forms.IntegerField(widget=forms.HiddenInput,required=False) product_slug = forms.CharField(widget=ProductInput(url="/order/search_product/")) item_value = forms.DecimalField() quantity = forms.IntegerField(initial=1)
Attachments
-
table_interface.gif
(16.3 KB) - added by alex
4 years ago.
-
table_validation.png
(10.7 KB) - added by alex
4 years ago.
-
complex_form_example.png
(35.1 KB) - added by alex
4 years ago.



