#4284 closed (wontfix)
forms containing MultiWidgets cannot be reconstructed with clean_data
Reported by: | Owned by: | nobody | |
---|---|---|---|
Component: | Forms | Version: | dev |
Severity: | Keywords: | MultiValueField MultiWidget clean_data decompress | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
This seems to be a design issue that may not be easy to resolve, but there is no easy way to reconstruct a MultiValueField with its own clean data. Whereas a normal field will accept data from clean_data, a MultiValueField expects it to be 'decompressed' first.
>>> from datetime import * >>> from django.newforms import * >>> >>> class MonthYearWidget(MultiWidget): ... def __init__(self,months=(),years=(),attrs=None): ... widgets = (Select(choices=months),Select(choices=years)) ... super(MonthYearWidget,self).__init__(widgets,attrs) ... def decompress(self,value): ... if value: ... return value.split('/') ... return ['', ''] ... >>> class MonthYearField(MultiValueField): ... def __init__(self,months=(),years=(),required=True,widget=None,label=None,initial=None): ... fields = (ChoiceField(choices=months),ChoiceField(choices=years)) ... widget = MonthYearWidget(months=months,years=years) ... super(MonthYearField,self).__init__(fields,required,widget,label,initial) ... def compress(self,data_list): ... if data_list: ... return '/'.join(data_list) ... return None ... >>> month_list = [x + 1 for x in xrange(12)] >>> months = [(m,m) for m in month_list] >>> year_list = [(date.today() + timedelta(days=366)*x).strftime("%Y") for x in xrange(10)] >>> years = [(y,y) for y in year_list] >>> >>> class PaymentForm(Form): ... ccn = RegexField('^\d{4}[ .-]?\d{4}[ .-]?\d{4}[ .-]?\d{4}$',widget=TextInput(attrs={'maxlength':19,'size':19})) ... exp_date = MonthYearField(months=months,years=years) ... >>> POST = {'ccn':'1234 5678 9012 3456','exp_date_0':'5','exp_date_1':'2007'} >>> pf = PaymentForm(POST) >>> pf.is_valid() True >>> pf.clean_data {'ccn': u'1234 5678 9012 3456', 'exp_date': u'5/2007'} >>> pf1 = PaymentForm(pf.clean_data) >>> pf1.is_valid() False >>> pf1.errors {'exp_date': [u'This field is required.']}
Change History (2)
comment:1 by , 17 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
comment:2 by , 17 years ago
I realize this is a won't fix issue, but since I just ran into the same problem I wanted to comment anyway. As for why you wouldn't just use the data from POST again... maybe it wasn't posted! My need was to repopulate a stored-settings form based on values stored in the database. I could have used initial, but I wanted to trigger validation on the old data in case the previous settings were no longer valid. It made sense to me anyway, and I was surprised it wasn't default behavior.
I did find a workaround by overriding the widgets value_from_datadict method to decompress the value if it exists in 'compressed' form. Something like this:
class MonthYearWidget(MultiWidget): ... def value_from_datadict(self,data,name): raw_val = data.get(name,None) if raw_val: value=self.decompress(raw_val) else: value = super(MonthYearWidget,self).value_from_datadict(data,name) return value
I don't think there's anywhere that says
cleaned_data
can be used to reconstruct another form.If you wanted to do this, why wouldn't you just use data (in this case
POST
) again?