Django administration provides three buttons for submitting the currently edited object. Each of them has a unique name and depending on the name that is sent to the server, the specific action is performed. I see this as an ugly solution and prefer to have a choice field in the form which would render as submit buttons with different values. Then the values would be checked instead of the names. Therefore, I created the MultipleSubmitButton
widget. When <input type="submit" value="Go" />
is used, the value sent to the server always matches the text on the button, but if <button type="submit" value="go">Go</button>
, the value and the human representation might differ.
To use the MultipleSubmitButton
widget, pass it to the widget parameter of a ChoiceField
like this:
SUBMIT_CHOICES = (
('save', _("Save")),
('save-add', _("Save and Add Another")),
)
class TestForm(forms.Form):
do = forms.ChoiceField(
widget=MultipleSubmitButton,
choices=SUBMIT_CHOICES,
)
When you print {{ form.do }}
in the template, the following HTML will be rendered:
<ul>
<li><button type="submit" name="do" value="save">Save</button></li>
<li><button type="submit" name="do" value="save-add">Save and Add Another</button></li>
</ul>
When you submit this form and check the validity of it, form.cleaned_data['do']
will return "save" or "save-add" depending on the submit button clicked.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | # -*- coding: utf-8 -*-
from django import forms
from django.utils.safestring import mark_safe
class SubmitButton(forms.Widget):
"""
A widget that handles a submit button.
"""
def __init__(self, name, value, label, attrs):
self.name, self.value, self.label = name, value, label
self.attrs = attrs
def __unicode__(self):
final_attrs = self.build_attrs(
self.attrs,
type="submit",
name=self.name,
value=self.value,
)
return mark_safe(u'<button%s>%s</button>' % (
forms.widgets.flatatt(final_attrs),
self.label,
))
class MultipleSubmitButton(forms.Select):
"""
A widget that handles a list of submit buttons.
"""
def __init__(self, attrs={}, choices=()):
self.attrs = attrs
self.choices = choices
def __iter__(self):
for value, label in self.choices:
yield SubmitButton(self.name, value, label, self.attrs.copy())
def __unicode__(self):
return '<button type="submit" />'
def render(self, name, value, attrs=None, choices=()):
"""Outputs a <ul> for this set of submit buttons."""
self.name = name
return mark_safe(u'<ul>\n%s\n</ul>' % u'\n'.join(
[u'<li>%s</li>' % force_unicode(w) for w in self],
))
def value_from_datadict(self, data, files, name):
"""
returns the value of the widget: IE posts inner HTML of the button
instead of the value.
"""
value = data.get(name, None)
if value in dict(self.choices):
return value
else:
inside_out_choices = dict([(v, k) for (k, v) in self.choices])
if value in inside_out_choices:
return inside_out_choices[value]
return None
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 1 week ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 5 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
amazingly useful drop-in replacement for a single radio-button choice form. thanks!
#
Excellent. I recommend adding the following import statement:
#
Please login first before commenting.