Changeset 8816
- Timestamp:
- 09/01/08 16:28:32 (3 months ago)
- Files:
-
- django/trunk/django/db/models/fields/__init__.py (modified) (4 diffs)
- django/trunk/django/forms/fields.py (modified) (4 diffs)
- django/trunk/django/forms/forms.py (modified) (8 diffs)
- django/trunk/django/forms/widgets.py (modified) (3 diffs)
- django/trunk/tests/modeltests/model_formsets/models.py (modified) (3 diffs)
- django/trunk/tests/regressiontests/forms/widgets.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/db/models/fields/__init__.py
r8806 r8816 232 232 def get_default(self): 233 233 "Returns the default value for this field." 234 if self. default is not NOT_PROVIDED:234 if self.has_default(): 235 235 if callable(self.default): 236 236 return self.default() … … 307 307 if self.has_default(): 308 308 defaults['initial'] = self.get_default() 309 309 if callable(self.default): 310 defaults['show_hidden_initial'] = True 310 311 if self.choices: 311 312 # Fields with choices get special treatment. … … 315 316 if self.null: 316 317 defaults['empty_value'] = None 317 318 318 form_class = forms.TypedChoiceField 319 320 319 # Many of the subclass-specific formfield arguments (min_value, 321 320 # max_value) don't apply for choice fields, so be sure to only pass … … 326 325 'error_messages'): 327 326 del kwargs[k] 328 329 327 defaults.update(kwargs) 330 328 return form_class(**defaults) django/trunk/django/forms/fields.py
r8771 r8816 29 29 30 30 from util import ErrorList, ValidationError 31 from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput, TimeInput 31 from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput, TimeInput, SplitHiddenDateTimeWidget 32 32 from django.core.files.uploadedfile import SimpleUploadedFile as UploadedFile 33 33 … … 60 60 61 61 def __init__(self, required=True, widget=None, label=None, initial=None, 62 help_text=None, error_messages=None ):62 help_text=None, error_messages=None, show_hidden_initial=False): 63 63 # required -- Boolean that specifies whether the field is required. 64 64 # True by default. … … 74 74 # is *not* used as a fallback if data isn't given. 75 75 # help_text -- An optional string to use as "help text" for this Field. 76 # show_hidden_initial -- Boolean that specifies if it is needed to render a 77 # hidden widget with initial value after widget. 76 78 if label is not None: 77 79 label = smart_unicode(label) 78 80 self.required, self.label, self.initial = required, label, initial 81 self.show_hidden_initial = show_hidden_initial 79 82 if help_text is None: 80 83 self.help_text = u'' … … 841 844 842 845 class SplitDateTimeField(MultiValueField): 846 hidden_widget = SplitHiddenDateTimeWidget 843 847 default_error_messages = { 844 848 'invalid_date': _(u'Enter a valid date.'), django/trunk/django/forms/forms.py
r8761 r8816 128 128 """ 129 129 return self.prefix and ('%s-%s' % (self.prefix, field_name)) or field_name 130 131 def add_initial_prefix(self, field_name): 132 """ 133 Add a 'initial' prefix for checking dynamic initial values 134 """ 135 return u'initial-%s' % self.add_prefix(field_name) 130 136 131 137 def _html_output(self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row): … … 246 252 """ 247 253 return bool(self.changed_data) 248 254 249 255 def _get_changed_data(self): 250 256 if self._changed_data is None: … … 259 265 prefixed_name = self.add_prefix(name) 260 266 data_value = field.widget.value_from_datadict(self.data, self.files, prefixed_name) 261 initial_value = self.initial.get(name, field.initial) 267 if not field.show_hidden_initial: 268 initial_value = self.initial.get(name, field.initial) 269 else: 270 initial_prefixed_name = self.add_initial_prefix(name) 271 hidden_widget = field.hidden_widget() 272 initial_value = hidden_widget.value_from_datadict( 273 self.data, self.files, initial_prefixed_name) 262 274 if field.widget._has_changed(initial_value, data_value): 263 275 self._changed_data.append(name) … … 301 313 self.name = name 302 314 self.html_name = form.add_prefix(name) 315 self.html_initial_name = form.add_initial_prefix(name) 303 316 if self.field.label is None: 304 317 self.label = pretty_name(name) … … 309 322 def __unicode__(self): 310 323 """Renders this field as an HTML widget.""" 324 if self.field.show_hidden_initial: 325 return self.as_widget() + self.as_hidden(only_initial=True) 311 326 return self.as_widget() 312 327 … … 319 334 errors = property(_errors) 320 335 321 def as_widget(self, widget=None, attrs=None ):336 def as_widget(self, widget=None, attrs=None, only_initial=False): 322 337 """ 323 338 Renders the field by rendering the passed widget, adding any HTML … … 331 346 if auto_id and 'id' not in attrs and 'id' not in widget.attrs: 332 347 attrs['id'] = auto_id 333 if not self.form.is_bound :348 if not self.form.is_bound or only_initial: 334 349 data = self.form.initial.get(self.name, self.field.initial) 335 350 if callable(data): … … 337 352 else: 338 353 data = self.data 339 return widget.render(self.html_name, data, attrs=attrs) 340 341 def as_text(self, attrs=None): 354 if not only_initial: 355 name = self.html_name 356 else: 357 name = self.html_initial_name 358 return widget.render(name, data, attrs=attrs) 359 360 def as_text(self, attrs=None, **kwargs): 342 361 """ 343 362 Returns a string of HTML for representing this as an <input type="text">. 344 363 """ 345 return self.as_widget(TextInput(), attrs )346 347 def as_textarea(self, attrs=None ):364 return self.as_widget(TextInput(), attrs, **kwargs) 365 366 def as_textarea(self, attrs=None, **kwargs): 348 367 "Returns a string of HTML for representing this as a <textarea>." 349 return self.as_widget(Textarea(), attrs )350 351 def as_hidden(self, attrs=None ):368 return self.as_widget(Textarea(), attrs, **kwargs) 369 370 def as_hidden(self, attrs=None, **kwargs): 352 371 """ 353 372 Returns a string of HTML for representing this as an <input type="hidden">. 354 373 """ 355 return self.as_widget(self.field.hidden_widget(), attrs )374 return self.as_widget(self.field.hidden_widget(), attrs, **kwargs) 356 375 357 376 def _data(self): django/trunk/django/forms/widgets.py
r8549 r8816 26 26 'FileInput', 'DateTimeInput', 'TimeInput', 'Textarea', 'CheckboxInput', 27 27 'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect', 28 'CheckboxSelectMultiple', 'MultiWidget', 'SplitDateTimeWidget', 28 'CheckboxSelectMultiple', 'MultiWidget', 29 'SplitDateTimeWidget', 29 30 ) 30 31 … … 618 619 initial = [u'' for x in range(0, len(data))] 619 620 else: 620 initial = self.decompress(initial) 621 if not isinstance(initial, list): 622 initial = self.decompress(initial) 621 623 for widget, initial, data in zip(self.widgets, initial, data): 622 624 if widget._has_changed(initial, data): … … 663 665 return [None, None] 664 666 667 class SplitHiddenDateTimeWidget(SplitDateTimeWidget): 668 """ 669 A Widget that splits datetime input into two <input type="hidden"> inputs. 670 """ 671 def __init__(self, attrs=None): 672 widgets = (HiddenInput(attrs=attrs), HiddenInput(attrs=attrs)) 673 super(SplitDateTimeWidget, self).__init__(widgets, attrs) 674 django/trunk/tests/modeltests/model_formsets/models.py
r8805 r8816 1 2 import datetime 3 4 from django import forms 1 5 from django.db import models 2 6 … … 93 97 serves_tacos = models.BooleanField() 94 98 99 # models for testing callable defaults (see bug #7975). If you define a model 100 # with a callable default value, you cannot rely on the initial value in a 101 # form. 102 class Person(models.Model): 103 name = models.CharField(max_length=128) 104 105 class Membership(models.Model): 106 person = models.ForeignKey(Person) 107 date_joined = models.DateTimeField(default=datetime.datetime.now) 108 karma = models.IntegerField() 95 109 96 110 __test__ = {'API_TESTS': """ … … 622 636 [{'__all__': [u'Price with this Price and Quantity already exists.']}] 623 637 638 # Use of callable defaults (see bug #7975). 639 640 >>> person = Person.objects.create(name='Ringo') 641 >>> FormSet = inlineformset_factory(Person, Membership, can_delete=False, extra=1) 642 >>> formset = FormSet(instance=person) 643 644 # Django will render a hidden field for model fields that have a callable 645 # default. This is required to ensure the value is tested for change correctly 646 # when determine what extra forms have changed to save. 647 648 >>> form = formset.forms[0] # this formset only has one form 649 >>> now = form.fields['date_joined'].initial 650 >>> print form.as_p() 651 <p><label for="id_membership_set-0-date_joined">Date joined:</label> <input type="text" name="membership_set-0-date_joined" value="..." id="id_membership_set-0-date_joined" /><input type="hidden" name="initial-membership_set-0-date_joined" value="..." id="id_membership_set-0-date_joined" /></p> 652 <p><label for="id_membership_set-0-karma">Karma:</label> <input type="text" name="membership_set-0-karma" id="id_membership_set-0-karma" /><input type="hidden" name="membership_set-0-id" id="id_membership_set-0-id" /></p> 653 654 # test for validation with callable defaults. Validations rely on hidden fields 655 656 >>> data = { 657 ... 'membership_set-TOTAL_FORMS': '1', 658 ... 'membership_set-INITIAL_FORMS': '0', 659 ... 'membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')), 660 ... 'initial-membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')), 661 ... 'membership_set-0-karma': '', 662 ... } 663 >>> formset = FormSet(data, instance=person) 664 >>> formset.is_valid() 665 True 666 667 # now test for when the data changes 668 669 >>> one_day_later = now + datetime.timedelta(days=1) 670 >>> filled_data = { 671 ... 'membership_set-TOTAL_FORMS': '1', 672 ... 'membership_set-INITIAL_FORMS': '0', 673 ... 'membership_set-0-date_joined': unicode(one_day_later.strftime('%Y-%m-%d %H:%M:%S')), 674 ... 'initial-membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')), 675 ... 'membership_set-0-karma': '', 676 ... } 677 >>> formset = FormSet(filled_data, instance=person) 678 >>> formset.is_valid() 679 False 680 681 # now test with split datetime fields 682 683 >>> class MembershipForm(forms.ModelForm): 684 ... date_joined = forms.SplitDateTimeField(initial=now) 685 ... class Meta: 686 ... model = Membership 687 ... def __init__(self, **kwargs): 688 ... super(MembershipForm, self).__init__(**kwargs) 689 ... self.fields['date_joined'].widget = forms.SplitDateTimeWidget() 690 691 >>> FormSet = inlineformset_factory(Person, Membership, form=MembershipForm, can_delete=False, extra=1) 692 >>> data = { 693 ... 'membership_set-TOTAL_FORMS': '1', 694 ... 'membership_set-INITIAL_FORMS': '0', 695 ... 'membership_set-0-date_joined_0': unicode(now.strftime('%Y-%m-%d')), 696 ... 'membership_set-0-date_joined_1': unicode(now.strftime('%H:%M:%S')), 697 ... 'initial-membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')), 698 ... 'membership_set-0-karma': '', 699 ... } 700 >>> formset = FormSet(data, instance=person) 701 >>> formset.is_valid() 702 True 703 704 624 705 """} django/trunk/tests/regressiontests/forms/widgets.py
r8601 r8816 1094 1094 u'<input type="text" name="date" value="2007-09-17 12:51:00" />' 1095 1095 1096 # TimeInput ############################################################### 1096 # TimeInput ################################################################### 1097 1097 1098 1098 >>> w = TimeInput() … … 1114 1114 >>> w.render('time', u'13:12:11') 1115 1115 u'<input type="text" name="time" value="13:12:11" />' 1116 1117 # SplitHiddenDateTimeWidget ################################################### 1118 1119 >>> from django.forms.widgets import SplitHiddenDateTimeWidget 1120 1121 >>> w = SplitHiddenDateTimeWidget() 1122 >>> w.render('date', '') 1123 u'<input type="hidden" name="date_0" /><input type="hidden" name="date_1" />' 1124 >>> w.render('date', d) 1125 u'<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:34" />' 1126 >>> w.render('date', datetime.datetime(2007, 9, 17, 12, 51, 34)) 1127 u'<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:34" />' 1128 >>> w.render('date', datetime.datetime(2007, 9, 17, 12, 51)) 1129 u'<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:00" />' 1130 1116 1131 """ 1117 1132
