Ticket #5609: trunk2.diff

File trunk2.diff, 29.1 KB (added by oggie_rob, 16 years ago)

newforms changes to support newforms-admin setting up widgets correctly

  • django/db/models/fields/__init__.py

     
    476476        return smart_unicode(value)
    477477
    478478    def formfield(self, **kwargs):
    479         defaults = {'max_length': self.max_length}
     479        defaults = {'max_length': self.max_length, 'length': 30}
    480480        defaults.update(kwargs)
    481481        return super(CharField, self).formfield(**defaults)
    482482
     
    484484class CommaSeparatedIntegerField(CharField):
    485485    def get_manipulator_field_objs(self):
    486486        return [oldforms.CommaSeparatedIntegerField]
     487   
     488    def formfield(self, **kwargs):
     489        defaults = {'length':20}
     490        defaults.update(kwargs)
     491        return super(CommaSeparatedIntegerField, self).formfield(**defaults)
    487492
    488493class DateField(Field):
    489494    empty_strings_allowed = False
     
    559564        return {self.attname: (val is not None and val.strftime("%Y-%m-%d") or '')}
    560565
    561566    def formfield(self, **kwargs):
    562         defaults = {'form_class': forms.DateField}
     567        defaults = {'form_class': forms.DateField, 'length':10, 'max_length':10}
    563568        defaults.update(kwargs)
    564569        return super(DateField, self).formfield(**defaults)
    565570
     
    624629                time_field: (val is not None and val.strftime("%H:%M:%S") or '')}
    625630
    626631    def formfield(self, **kwargs):
    627         defaults = {'form_class': forms.DateTimeField}
     632        defaults = {'form_class': forms.DateTimeField, 'length':20, 'max_length':20}
    628633        defaults.update(kwargs)
    629634        return super(DateTimeField, self).formfield(**defaults)
    630635
     
    684689            'max_digits': self.max_digits,
    685690            'decimal_places': self.decimal_places,
    686691            'form_class': forms.DecimalField,
     692            'length': self.max_digits and self.max_digits + 2 or 30,
    687693        }
     694        if self.max_digits:
     695            defaults['max_length'] = self.max_digits + 2
    688696        defaults.update(kwargs)
    689697        return super(DecimalField, self).formfield(**defaults)
    690698
     
    703711        validators.isValidEmail(field_data, all_data)
    704712
    705713    def formfield(self, **kwargs):
    706         defaults = {'form_class': forms.EmailField}
     714        defaults = {'form_class': forms.EmailField, 'length': 50, 'max_length': self.max_length}
    707715        defaults.update(kwargs)
    708716        return super(EmailField, self).formfield(**defaults)
    709717
     
    869877        return [oldforms.IntegerField]
    870878
    871879    def formfield(self, **kwargs):
    872         defaults = {'form_class': forms.IntegerField}
     880        defaults = {'form_class': forms.IntegerField, 'length': 10}
    873881        defaults.update(kwargs)
    874882        return super(IntegerField, self).formfield(**defaults)
    875883
     
    886894        validators.isValidIPAddress4(field_data, None)
    887895
    888896    def formfield(self, **kwargs):
    889         defaults = {'form_class': forms.IPAddressField}
     897        defaults = {'form_class': forms.IPAddressField, 'length': 15, 'max_length': 15}
    890898        defaults.update(kwargs)
    891899        return super(IPAddressField, self).formfield(**defaults)
    892900
     
    915923
    916924    def formfield(self, **kwargs):
    917925        from django.contrib.localflavor.us.forms import USPhoneNumberField
    918         defaults = {'form_class': USPhoneNumberField}
     926        defaults = {'form_class': USPhoneNumberField}
     927        # 'length':12, 'max_length': 12 aren't used as USPhoneNumberField extends Field rather than CharField
    919928        defaults.update(kwargs)
    920929        return super(PhoneNumberField, self).formfield(**defaults)
    921930
     
    924933        return [oldforms.PositiveIntegerField]
    925934   
    926935    def formfield(self, **kwargs):
    927         defaults = {'min_value': 0}
     936        defaults = {'min_value': 0, 'length': 10}
    928937        defaults.update(kwargs)
    929938        return super(PositiveIntegerField, self).formfield(**defaults)
    930939
     
    933942        return [oldforms.PositiveSmallIntegerField]
    934943
    935944    def formfield(self, **kwargs):
    936         defaults = {'min_value': 0}
     945        defaults = {'min_value': 0, 'length': 5, 'max_length': 5}
    937946        defaults.update(kwargs)
    938947        return super(PositiveSmallIntegerField, self).formfield(**defaults)
    939948
     
    950959    def get_manipulator_field_objs(self):
    951960        return [oldforms.SmallIntegerField]
    952961
     962    def formfield(self, **kwargs):
     963        defaults = {'length': 5, 'max_length': 5}
     964        defaults.update(kwargs)
     965        return super(SmallIntegerField, self).formfield(**defaults)
     966
    953967class TextField(Field):
    954968    def get_manipulator_field_objs(self):
    955969        return [oldforms.LargeTextField]
     
    10161030        return {self.attname: (val is not None and val.strftime("%H:%M:%S") or '')}
    10171031
    10181032    def formfield(self, **kwargs):
    1019         defaults = {'form_class': forms.TimeField}
     1033        defaults = {'form_class': forms.TimeField, 'length': 8, 'max_length': 8}
    10201034        defaults.update(kwargs)
    10211035        return super(TimeField, self).formfield(**defaults)
    10221036
     
    10351049        return "CharField"
    10361050
    10371051    def formfield(self, **kwargs):
    1038         defaults = {'form_class': forms.URLField, 'verify_exists': self.verify_exists}
     1052        defaults = {'form_class': forms.URLField, 'verify_exists': self.verify_exists, 'length': 50}
    10391053        defaults.update(kwargs)
    10401054        return super(URLField, self).formfield(**defaults)
    10411055
  • django/newforms/fields.py

     
    2020from django.utils.encoding import StrAndUnicode, smart_unicode, smart_str
    2121
    2222from util import ErrorList, ValidationError
    23 from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput
     23from widgets import WidgetDict, TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput
    2424
    2525
    2626__all__ = (
     
    110110        any HTML attributes that should be added to the Widget, based on this
    111111        Field.
    112112        """
    113         return {}
     113        if self.required:
     114            return WidgetDict({'class': 'required'})
     115        return WidgetDict()
    114116
    115117    def __deepcopy__(self, memo):
    116118        result = copy.copy(self)
     
    124126        'min_length': _(u'Ensure this value has at least %(min)d characters (it has %(length)d).'),
    125127    }
    126128
    127     def __init__(self, max_length=None, min_length=None, *args, **kwargs):
    128         self.max_length, self.min_length = max_length, min_length
     129    def __init__(self, max_length=None, min_length=None, length=None, *args, **kwargs):
     130        self.max_length, self.min_length, self.length = max_length, min_length, length
    129131        super(CharField, self).__init__(*args, **kwargs)
    130132
    131133    def clean(self, value):
     
    142144        return value
    143145
    144146    def widget_attrs(self, widget):
    145         if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)):
     147        attrs = super(CharField, self).widget_attrs(widget)
     148        if self.length is not None:
     149            attrs['size'] = str(self.length)
     150        if self.max_length is not None:
    146151            # The HTML attribute is maxlength, not max_length.
    147             return {'maxlength': str(self.max_length)}
     152            attrs['maxlength'] = str(self.max_length)
     153        return attrs
    148154
    149 class IntegerField(Field):
     155class IntegerField(CharField):
    150156    default_error_messages = {
    151157        'invalid': _(u'Enter a whole number.'),
    152158        'max_value': _(u'Ensure this value is less than or equal to %s.'),
     
    183189    }
    184190
    185191    def __init__(self, max_value=None, min_value=None, *args, **kwargs):
     192        super(FloatField, self).__init__(*args, **kwargs)
    186193        self.max_value, self.min_value = max_value, min_value
    187         Field.__init__(self, *args, **kwargs)
    188194
    189195    def clean(self, value):
    190196        """
     
    204210            raise ValidationError(self.error_messages['min_value'] % self.min_value)
    205211        return value
    206212
    207 class DecimalField(Field):
     213class DecimalField(CharField):
    208214    default_error_messages = {
    209215        'invalid': _(u'Enter a number.'),
    210216        'max_value': _(u'Ensure this value is less than or equal to %s.'),
     
    215221    }
    216222
    217223    def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs):
     224        super(DecimalField, self).__init__(*args, **kwargs)
    218225        self.max_value, self.min_value = max_value, min_value
    219226        self.max_digits, self.decimal_places = max_digits, decimal_places
    220         Field.__init__(self, *args, **kwargs)
    221227
    222228    def clean(self, value):
    223229        """
     
    257263    '%d %B %Y', '%d %B, %Y',            # '25 October 2006', '25 October, 2006'
    258264)
    259265
    260 class DateField(Field):
     266class DateField(CharField):
    261267    default_error_messages = {
    262268        'invalid': _(u'Enter a valid date.'),
    263269    }
     
    290296    '%H:%M',        # '14:30'
    291297)
    292298
    293 class TimeField(Field):
     299class TimeField(CharField):
    294300    default_error_messages = {
    295301        'invalid': _(u'Enter a valid time.')
    296302    }
     
    328334    '%m/%d/%y',              # '10/25/06'
    329335)
    330336
    331 class DateTimeField(Field):
     337class DateTimeField(CharField):
    332338    widget = DateTimeInput
    333339    default_error_messages = {
    334340        'invalid': _(u'Enter a valid date/time.'),
     
    375381            error_messages = kwargs.get('error_messages') or {}
    376382            error_messages['invalid'] = error_message
    377383            kwargs['error_messages'] = error_messages
    378         super(RegexField, self).__init__(max_length, min_length, *args, **kwargs)
     384        super(RegexField, self).__init__(max_length=max_length, min_length=min_length, *args, **kwargs)
    379385        if isinstance(regex, basestring):
    380386            regex = re.compile(regex)
    381387        self.regex = regex
     
    493499        'invalid_link': _(u'This URL appears to be a broken link.'),
    494500    }
    495501
    496     def __init__(self, max_length=None, min_length=None, verify_exists=False,
     502    def __init__(self, max_length=None, min_length=None, length=None, verify_exists=False,
    497503            validator_user_agent=URL_VALIDATOR_USER_AGENT, *args, **kwargs):
    498         super(URLField, self).__init__(url_re, max_length, min_length, *args,
    499                                        **kwargs)
     504        super(URLField, self).__init__(regex=url_re, max_length=max_length,
     505                                       min_length=min_length, length=length, *args, **kwargs)
    500506        self.verify_exists = verify_exists
    501507        self.user_agent = validator_user_agent
    502508
     
    557563
    558564    def __init__(self, choices=(), required=True, widget=None, label=None,
    559565                 initial=None, help_text=None, *args, **kwargs):
    560         super(ChoiceField, self).__init__(required, widget, label, initial,
    561                                           help_text, *args, **kwargs)
     566        super(ChoiceField, self).__init__(required=required, widget=widget, label=label,
     567                                          initial=initial, help_text=help_text,
     568                                          *args, **kwargs)
    562569        self.choices = choices
    563570
    564571    def _get_choices(self):
     
    725732        if 'error_messages' in kwargs:
    726733            errors.update(kwargs['error_messages'])
    727734        fields = (
    728             DateField(error_messages={'invalid': errors['invalid_date']}),
    729             TimeField(error_messages={'invalid': errors['invalid_time']}),
     735            DateField(error_messages={'invalid': errors['invalid_date']}, max_length=10),
     736            TimeField(error_messages={'invalid': errors['invalid_time']}, max_length=8),
    730737        )
    731         super(SplitDateTimeField, self).__init__(fields, *args, **kwargs)
     738        super(SplitDateTimeField, self).__init__(fields=fields, *args, **kwargs)
    732739
    733740    def compress(self, data_list):
    734741        if data_list:
     
    749756    }
    750757
    751758    def __init__(self, *args, **kwargs):
    752         super(IPAddressField, self).__init__(ipv4_re, *args, **kwargs)
     759        super(IPAddressField, self).__init__(regex=ipv4_re, *args, **kwargs)
  • django/newforms/widgets.py

     
    1818from util import flatatt
    1919
    2020__all__ = (
    21     'Widget', 'TextInput', 'PasswordInput',
     21    'WidgetDict', 'Widget', 'TextInput', 'PasswordInput',
    2222    'HiddenInput', 'MultipleHiddenInput',
    2323    'FileInput', 'DateTimeInput', 'Textarea', 'CheckboxInput',
    2424    'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect',
    2525    'CheckboxSelectMultiple', 'MultiWidget', 'SplitDateTimeWidget',
    2626)
    2727
     28
     29class WidgetDict(dict):
     30    """
     31    Tracks most attributes normally - except css classes, which are
     32    appended instead of replaced when you set/update the variable.
     33
     34    If you truly need to override the css class value, just delete and reset it
     35    """
     36    def _css_class_string(self, value):
     37        """
     38        Returns string containing combination of all classes
     39        """
     40        if not value:
     41            return self.get('class', '')       
     42        my_classes = set(self.get('class', '').split(' '))
     43        my_classes.update(value.split(' '))
     44        my_classes.discard('')
     45        return ' '.join(my_classes)
     46
     47    def __setitem__(self, key, value):
     48        if key == 'class':
     49            value = self._css_class_string(value)
     50        super(WidgetDict, self).__setitem__(key, value)
     51
     52    def update(self, new_dict):
     53        my_dict = new_dict.copy()
     54        if my_dict.has_key('class'):
     55            my_dict['class'] = self._css_class_string(my_dict.get('class'))
     56        super(WidgetDict, self).update(my_dict)
     57
    2858class Widget(object):
    2959    is_hidden = False          # Determines whether this corresponds to an <input type="hidden">.
    3060    needs_multipart_form = False # Determines does this widget need multipart-encrypted form
    3161
    3262    def __init__(self, attrs=None):
    3363        if attrs is not None:
    34             self.attrs = attrs.copy()
     64            self.attrs = WidgetDict(attrs)
    3565        else:
    36             self.attrs = {}
     66            self.attrs = WidgetDict()
    3767
    3868    def __deepcopy__(self, memo):
    3969        obj = copy.copy(self)
     
    5282
    5383    def build_attrs(self, extra_attrs=None, **kwargs):
    5484        "Helper function for building an attribute dictionary."
    55         attrs = dict(self.attrs, **kwargs)
     85        attrs = WidgetDict(self.attrs)
     86        attrs.update(kwargs)
    5687        if extra_attrs:
    5788            attrs.update(extra_attrs)
    5889        return attrs
  • tests/regressiontests/forms/extra.py

     
    232232...     field1 = ComplexField(widget=w)
    233233>>> f = ComplexFieldForm()
    234234>>> print f
    235 <tr><th><label for="id_field1_0">Field1:</label></th><td><input type="text" name="field1_0" id="id_field1_0" />
    236 <select multiple="multiple" name="field1_1" id="id_field1_1">
     235<tr><th><label for="id_field1_0">Field1:</label></th><td><input id="id_field1_0" type="text" name="field1_0" class="required" />
     236<select multiple="multiple" id="id_field1_1" name="field1_1" class="required">
    237237<option value="J">John</option>
    238238<option value="P">Paul</option>
    239239<option value="G">George</option>
    240240<option value="R">Ringo</option>
    241241</select>
    242 <input type="text" name="field1_2_0" id="id_field1_2_0" /><input type="text" name="field1_2_1" id="id_field1_2_1" /></td></tr>
     242<input id="id_field1_2_0" type="text" name="field1_2_0" class="required" /><input id="id_field1_2_1" type="text" name="field1_2_1" class="required" /></td></tr>
    243243
    244244>>> f = ComplexFieldForm({'field1_0':'some text','field1_1':['J','P'], 'field1_2_0':'2007-04-25', 'field1_2_1':'06:24:00'})
    245245>>> print f
    246 <tr><th><label for="id_field1_0">Field1:</label></th><td><input type="text" name="field1_0" value="some text" id="id_field1_0" />
    247 <select multiple="multiple" name="field1_1" id="id_field1_1">
     246<tr><th><label for="id_field1_0">Field1:</label></th><td><input id="id_field1_0" type="text" name="field1_0" value="some text" class="required" />
     247<select multiple="multiple" id="id_field1_1" name="field1_1" class="required">
    248248<option value="J" selected="selected">John</option>
    249249<option value="P" selected="selected">Paul</option>
    250250<option value="G">George</option>
    251251<option value="R">Ringo</option>
    252252</select>
    253 <input type="text" name="field1_2_0" value="2007-04-25" id="id_field1_2_0" /><input type="text" name="field1_2_1" value="06:24:00" id="id_field1_2_1" /></td></tr>
     253<input id="id_field1_2_0" type="text" name="field1_2_0" value="2007-04-25" class="required" /><input id="id_field1_2_1" type="text" name="field1_2_1" value="06:24:00" class="required" /></td></tr>
    254254
    255255>>> f.cleaned_data
    256256{'field1': u'some text,JP,2007-04-25 06:24:00'}
     
    373373>>> print f.as_p()
    374374<p>Name: <input type="text" name="name" maxlength="50" /></p>
    375375<div class="errorlist"><div class="error">Enter a valid e-mail address.</div></div>
    376 <p>Email: <input type="text" name="email" value="invalid" /></p>
     376<p>Email: <input type="text" class="required" value="invalid" name="email" /></p>
    377377<div class="errorlist"><div class="error">This field is required.</div></div>
    378 <p>Comment: <input type="text" name="comment" /></p>
     378<p>Comment: <input type="text" class="required" name="comment" /></p>
    379379
    380380#################################
    381381# Test multipart-encoded form #
  • tests/regressiontests/forms/forms.py

     
    3939>>> p.cleaned_data
    4040{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
    4141>>> print p['first_name']
    42 <input type="text" name="first_name" value="John" id="id_first_name" />
     42<input id="id_first_name" type="text" class="required" value="John" name="first_name" />
    4343>>> print p['last_name']
    44 <input type="text" name="last_name" value="Lennon" id="id_last_name" />
     44<input id="id_last_name" type="text" class="required" value="Lennon" name="last_name" />
    4545>>> print p['birthday']
    46 <input type="text" name="birthday" value="1940-10-9" id="id_birthday" />
     46<input id="id_birthday" type="text" class="required" value="1940-10-9" name="birthday" />
    4747>>> print p['nonexistentfield']
    4848Traceback (most recent call last):
    4949...
     
    5151
    5252>>> for boundfield in p:
    5353...     print boundfield
    54 <input type="text" name="first_name" value="John" id="id_first_name" />
    55 <input type="text" name="last_name" value="Lennon" id="id_last_name" />
    56 <input type="text" name="birthday" value="1940-10-9" id="id_birthday" />
     54<input id="id_first_name" type="text" class="required" value="John" name="first_name" />
     55<input id="id_last_name" type="text" class="required" value="Lennon" name="last_name" />
     56<input id="id_birthday" type="text" class="required" value="1940-10-9" name="birthday" />
    5757>>> for boundfield in p:
    5858...     print boundfield.label, boundfield.data
    5959First name John
    6060Last name Lennon
    6161Birthday 1940-10-9
    6262>>> print p
    63 <tr><th><label for="id_first_name">First name:</label></th><td><input type="text" name="first_name" value="John" id="id_first_name" /></td></tr>
    64 <tr><th><label for="id_last_name">Last name:</label></th><td><input type="text" name="last_name" value="Lennon" id="id_last_name" /></td></tr>
    65 <tr><th><label for="id_birthday">Birthday:</label></th><td><input type="text" name="birthday" value="1940-10-9" id="id_birthday" /></td></tr>
     63<tr><th><label for="id_first_name">First name:</label></th><td><input id="id_first_name" type="text" class="required" value="John" name="first_name" /></td></tr>
     64<tr><th><label for="id_last_name">Last name:</label></th><td><input id="id_last_name" type="text" class="required" value="Lennon" name="last_name" /></td></tr>
     65<tr><th><label for="id_birthday">Birthday:</label></th><td><input id="id_birthday" type="text" class="required" value="1940-10-9" name="birthday" /></td></tr>
    6666
    6767Empty dictionaries are valid, too.
    6868>>> p = Person({})
     
    7777...
    7878AttributeError: 'Person' object has no attribute 'cleaned_data'
    7979>>> print p
    80 <tr><th><label for="id_first_name">First name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="first_name" id="id_first_name" /></td></tr>
    81 <tr><th><label for="id_last_name">Last name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="last_name" id="id_last_name" /></td></tr>
    82 <tr><th><label for="id_birthday">Birthday:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="birthday" id="id_birthday" /></td></tr>
     80<tr><th><label for="id_first_name">First name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input id="id_first_name" type="text" class="required" name="first_name" /></td></tr>
     81<tr><th><label for="id_last_name">Last name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input id="id_last_name" type="text" class="required" name="last_name" /></td></tr>
     82<tr><th><label for="id_birthday">Birthday:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input id="id_birthday" type="text" class="required" name="birthday" /></td></tr>
    8383>>> print p.as_table()
    84 <tr><th><label for="id_first_name">First name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="first_name" id="id_first_name" /></td></tr>
    85 <tr><th><label for="id_last_name">Last name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="last_name" id="id_last_name" /></td></tr>
    86 <tr><th><label for="id_birthday">Birthday:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="birthday" id="id_birthday" /></td></tr>
     84<tr><th><label for="id_first_name">First name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input id="id_first_name" class="required" type="text" name="first_name" /></td></tr>
     85<tr><th><label for="id_last_name">Last name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input id="id_last_name" type="text" class="required" name="last_name" /></td></tr>
     86<tr><th><label for="id_birthday">Birthday:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input id="id_birthday" type="text" class="required" name="birthday" /></td></tr>
    8787>>> print p.as_ul()
    88 <li><ul class="errorlist"><li>This field is required.</li></ul><label for="id_first_name">First name:</label> <input type="text" name="first_name" id="id_first_name" /></li>
    89 <li><ul class="errorlist"><li>This field is required.</li></ul><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" /></li>
    90 <li><ul class="errorlist"><li>This field is required.</li></ul><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" /></li>
     88<li><ul class="errorlist"><li>This field is required.</li></ul><label for="id_first_name">First name:</label> <input id="id_first_name" type="text" class="required" name="first_name" /></li>
     89<li><ul class="errorlist"><li>This field is required.</li></ul><label for="id_last_name">Last name:</label> <input id="id_last_name" type="text" class="required" name="last_name" /></li>
     90<li><ul class="errorlist"><li>This field is required.</li></ul><label for="id_birthday">Birthday:</label> <input id="id_birthday" type="text" class="required" name="birthday" /></li>
    9191>>> print p.as_p()
    9292<ul class="errorlist"><li>This field is required.</li></ul>
    93 <p><label for="id_first_name">First name:</label> <input type="text" name="first_name" id="id_first_name" /></p>
     93<p><label for="id_first_name">First name:</label> <input id="id_first_name" type="text" class="required" name="first_name" /></p>
    9494<ul class="errorlist"><li>This field is required.</li></ul>
    95 <p><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" /></p>
     95<p><label for="id_last_name">Last name:</label> <input id="id_last_name" type="text" class="required" name="last_name" /></p>
    9696<ul class="errorlist"><li>This field is required.</li></ul>
    97 <p><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" /></p>
     97<p><label for="id_birthday">Birthday:</label> <input id="id_birthday" type="text" class="required" name="birthday" /></p>
    9898
    9999If you don't pass any values to the Form's __init__(), or if you pass None,
    100100the Form will be considered unbound and won't do any validation. Form.errors
  • tests/regressiontests/forms/widgets.py

     
    1919render itself, given a field name and some data. Widgets don't perform
    2020validation.
    2121
     22WidgetDict appends css class information instead of overwriting it.
     23
     24# WidgetDict ##################################################################
     25>>> w = WidgetDict({'class': 'test run'})
     26>>> w['class'] = 'another'
     27>>> print w['class']
     28test run another
     29>>> w.update({'class': 'fourth', 'ignore': 'foo'})
     30>>> print w['class']
     31test another run fourth
     32
    2233# TextInput Widget ############################################################
    2334
    2435>>> w = TextInput()
     
    4859'attrs' passed to render() get precedence over those passed to the constructor:
    4960>>> w = TextInput(attrs={'class': 'pretty'})
    5061>>> w.render('email', '', attrs={'class': 'special'})
    51 u'<input type="text" class="special" name="email" />'
     62u'<input type="text" class="pretty special" name="email" />'
    5263
    5364# PasswordInput Widget ############################################################
    5465
     
    7485'attrs' passed to render() get precedence over those passed to the constructor:
    7586>>> w = PasswordInput(attrs={'class': 'pretty'})
    7687>>> w.render('email', '', attrs={'class': 'special'})
    77 u'<input type="password" class="special" name="email" />'
     88u'<input type="password" class="pretty special" name="email" />'
    7889
    7990>>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
    8091u'<input type="password" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />'
     
    119130'attrs' passed to render() get precedence over those passed to the constructor:
    120131>>> w = HiddenInput(attrs={'class': 'pretty'})
    121132>>> w.render('email', '', attrs={'class': 'special'})
    122 u'<input type="hidden" class="special" name="email" />'
     133u'<input type="hidden" class="pretty special" name="email" />'
    123134
    124135>>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
    125136u'<input type="hidden" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />'
     
    127138'attrs' passed to render() get precedence over those passed to the constructor:
    128139>>> w = HiddenInput(attrs={'class': 'pretty'})
    129140>>> w.render('email', '', attrs={'class': 'special'})
    130 u'<input type="hidden" class="special" name="email" />'
     141u'<input type="hidden" class="pretty special" name="email" />'
    131142
    132143Boolean values are rendered to their string forms ("True" and "False").
    133144>>> w = HiddenInput()
     
    166177'attrs' passed to render() get precedence over those passed to the constructor:
    167178>>> w = MultipleHiddenInput(attrs={'class': 'pretty'})
    168179>>> w.render('email', ['foo@example.com'], attrs={'class': 'special'})
    169 u'<input type="hidden" class="special" value="foo@example.com" name="email" />'
     180u'<input type="hidden" class="pretty special" value="foo@example.com" name="email" />'
    170181
    171182>>> w.render('email', ['ŠĐĆŽćžšđ'], attrs={'class': 'fun'})
    172183u'<input type="hidden" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />'
     
    174185'attrs' passed to render() get precedence over those passed to the constructor:
    175186>>> w = MultipleHiddenInput(attrs={'class': 'pretty'})
    176187>>> w.render('email', ['foo@example.com'], attrs={'class': 'special'})
    177 u'<input type="hidden" class="special" value="foo@example.com" name="email" />'
     188u'<input type="hidden" class="pretty special" value="foo@example.com" name="email" />'
    178189
    179190# FileInput Widget ############################################################
    180191
     
    228239'attrs' passed to render() get precedence over those passed to the constructor:
    229240>>> w = Textarea(attrs={'class': 'pretty'})
    230241>>> w.render('msg', '', attrs={'class': 'special'})
    231 u'<textarea rows="10" cols="40" name="msg" class="special"></textarea>'
     242u'<textarea rows="10" cols="40" name="msg" class="pretty special"></textarea>'
    232243
    233244>>> w.render('msg', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
    234245u'<textarea rows="10" cols="40" name="msg" class="fun">\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111</textarea>'
     
    261272'attrs' passed to render() get precedence over those passed to the constructor:
    262273>>> w = CheckboxInput(attrs={'class': 'pretty'})
    263274>>> w.render('is_cool', '', attrs={'class': 'special'})
    264 u'<input type="checkbox" class="special" name="is_cool" />'
     275u'<input type="checkbox" class="pretty special" name="is_cool" />'
    265276
    266277You can pass 'check_test' to the constructor. This is a callable that takes the
    267278value and returns True if the box should be checked.
Back to Top