Index: django/db/models/fields/__init__.py
===================================================================
--- django/db/models/fields/__init__.py	(revision 6860)
+++ django/db/models/fields/__init__.py	(working copy)
@@ -476,7 +476,7 @@
         return smart_unicode(value)
 
     def formfield(self, **kwargs):
-        defaults = {'max_length': self.max_length}
+        defaults = {'max_length': self.max_length, 'length': 30}
         defaults.update(kwargs)
         return super(CharField, self).formfield(**defaults)
 
@@ -484,6 +484,11 @@
 class CommaSeparatedIntegerField(CharField):
     def get_manipulator_field_objs(self):
         return [oldforms.CommaSeparatedIntegerField]
+    
+    def formfield(self, **kwargs):
+        defaults = {'length':20}
+        defaults.update(kwargs)
+        return super(CommaSeparatedIntegerField, self).formfield(**defaults)
 
 class DateField(Field):
     empty_strings_allowed = False
@@ -559,7 +564,7 @@
         return {self.attname: (val is not None and val.strftime("%Y-%m-%d") or '')}
 
     def formfield(self, **kwargs):
-        defaults = {'form_class': forms.DateField}
+        defaults = {'form_class': forms.DateField, 'length':10, 'max_length':10}
         defaults.update(kwargs)
         return super(DateField, self).formfield(**defaults)
 
@@ -624,7 +629,7 @@
                 time_field: (val is not None and val.strftime("%H:%M:%S") or '')}
 
     def formfield(self, **kwargs):
-        defaults = {'form_class': forms.DateTimeField}
+        defaults = {'form_class': forms.DateTimeField, 'length':20, 'max_length':20}
         defaults.update(kwargs)
         return super(DateTimeField, self).formfield(**defaults)
 
@@ -684,7 +689,10 @@
             'max_digits': self.max_digits,
             'decimal_places': self.decimal_places,
             'form_class': forms.DecimalField,
+            'length': self.max_digits and self.max_digits + 2 or 30,
         }
+        if self.max_digits:
+            defaults['max_length'] = self.max_digits + 2
         defaults.update(kwargs)
         return super(DecimalField, self).formfield(**defaults)
 
@@ -703,7 +711,7 @@
         validators.isValidEmail(field_data, all_data)
 
     def formfield(self, **kwargs):
-        defaults = {'form_class': forms.EmailField}
+        defaults = {'form_class': forms.EmailField, 'length': 50, 'max_length': self.max_length}
         defaults.update(kwargs)
         return super(EmailField, self).formfield(**defaults)
 
@@ -869,7 +877,7 @@
         return [oldforms.IntegerField]
 
     def formfield(self, **kwargs):
-        defaults = {'form_class': forms.IntegerField}
+        defaults = {'form_class': forms.IntegerField, 'length': 10}
         defaults.update(kwargs)
         return super(IntegerField, self).formfield(**defaults)
 
@@ -886,7 +894,7 @@
         validators.isValidIPAddress4(field_data, None)
 
     def formfield(self, **kwargs):
-        defaults = {'form_class': forms.IPAddressField}
+        defaults = {'form_class': forms.IPAddressField, 'length': 15, 'max_length': 15}
         defaults.update(kwargs)
         return super(IPAddressField, self).formfield(**defaults)
 
@@ -915,7 +923,8 @@
 
     def formfield(self, **kwargs):
         from django.contrib.localflavor.us.forms import USPhoneNumberField
-        defaults = {'form_class': USPhoneNumberField}
+        defaults = {'form_class': USPhoneNumberField} 
+        # 'length':12, 'max_length': 12 aren't used as USPhoneNumberField extends Field rather than CharField
         defaults.update(kwargs)
         return super(PhoneNumberField, self).formfield(**defaults)
 
@@ -924,7 +933,7 @@
         return [oldforms.PositiveIntegerField]
     
     def formfield(self, **kwargs):
-        defaults = {'min_value': 0}
+        defaults = {'min_value': 0, 'length': 10}
         defaults.update(kwargs)
         return super(PositiveIntegerField, self).formfield(**defaults) 
 
@@ -933,7 +942,7 @@
         return [oldforms.PositiveSmallIntegerField]
 
     def formfield(self, **kwargs):
-        defaults = {'min_value': 0}
+        defaults = {'min_value': 0, 'length': 5, 'max_length': 5}
         defaults.update(kwargs)
         return super(PositiveSmallIntegerField, self).formfield(**defaults) 
 
@@ -950,6 +959,11 @@
     def get_manipulator_field_objs(self):
         return [oldforms.SmallIntegerField]
 
+    def formfield(self, **kwargs):
+        defaults = {'length': 5, 'max_length': 5}
+        defaults.update(kwargs)
+        return super(SmallIntegerField, self).formfield(**defaults) 
+
 class TextField(Field):
     def get_manipulator_field_objs(self):
         return [oldforms.LargeTextField]
@@ -1016,7 +1030,7 @@
         return {self.attname: (val is not None and val.strftime("%H:%M:%S") or '')}
 
     def formfield(self, **kwargs):
-        defaults = {'form_class': forms.TimeField}
+        defaults = {'form_class': forms.TimeField, 'length': 8, 'max_length': 8}
         defaults.update(kwargs)
         return super(TimeField, self).formfield(**defaults)
 
@@ -1035,7 +1049,7 @@
         return "CharField"
 
     def formfield(self, **kwargs):
-        defaults = {'form_class': forms.URLField, 'verify_exists': self.verify_exists}
+        defaults = {'form_class': forms.URLField, 'verify_exists': self.verify_exists, 'length': 50}
         defaults.update(kwargs)
         return super(URLField, self).formfield(**defaults)
 
Index: django/newforms/fields.py
===================================================================
--- django/newforms/fields.py	(revision 6860)
+++ django/newforms/fields.py	(working copy)
@@ -20,7 +20,7 @@
 from django.utils.encoding import StrAndUnicode, smart_unicode, smart_str
 
 from util import ErrorList, ValidationError
-from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput
+from widgets import WidgetDict, TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput
 
 
 __all__ = (
@@ -110,7 +110,9 @@
         any HTML attributes that should be added to the Widget, based on this
         Field.
         """
-        return {}
+        if self.required:
+            return WidgetDict({'class': 'required'})
+        return WidgetDict()
 
     def __deepcopy__(self, memo):
         result = copy.copy(self)
@@ -124,8 +126,8 @@
         'min_length': _(u'Ensure this value has at least %(min)d characters (it has %(length)d).'),
     }
 
-    def __init__(self, max_length=None, min_length=None, *args, **kwargs):
-        self.max_length, self.min_length = max_length, min_length
+    def __init__(self, max_length=None, min_length=None, length=None, *args, **kwargs):
+        self.max_length, self.min_length, self.length = max_length, min_length, length
         super(CharField, self).__init__(*args, **kwargs)
 
     def clean(self, value):
@@ -142,11 +144,15 @@
         return value
 
     def widget_attrs(self, widget):
-        if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)):
+        attrs = super(CharField, self).widget_attrs(widget)
+        if self.length is not None:
+            attrs['size'] = str(self.length)
+        if self.max_length is not None:
             # The HTML attribute is maxlength, not max_length.
-            return {'maxlength': str(self.max_length)}
+            attrs['maxlength'] = str(self.max_length)
+        return attrs
 
-class IntegerField(Field):
+class IntegerField(CharField):
     default_error_messages = {
         'invalid': _(u'Enter a whole number.'),
         'max_value': _(u'Ensure this value is less than or equal to %s.'),
@@ -183,8 +189,8 @@
     }
 
     def __init__(self, max_value=None, min_value=None, *args, **kwargs):
+        super(FloatField, self).__init__(*args, **kwargs)
         self.max_value, self.min_value = max_value, min_value
-        Field.__init__(self, *args, **kwargs)
 
     def clean(self, value):
         """
@@ -204,7 +210,7 @@
             raise ValidationError(self.error_messages['min_value'] % self.min_value)
         return value
 
-class DecimalField(Field):
+class DecimalField(CharField):
     default_error_messages = {
         'invalid': _(u'Enter a number.'),
         'max_value': _(u'Ensure this value is less than or equal to %s.'),
@@ -215,9 +221,9 @@
     }
 
     def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs):
+        super(DecimalField, self).__init__(*args, **kwargs)
         self.max_value, self.min_value = max_value, min_value
         self.max_digits, self.decimal_places = max_digits, decimal_places
-        Field.__init__(self, *args, **kwargs)
 
     def clean(self, value):
         """
@@ -257,7 +263,7 @@
     '%d %B %Y', '%d %B, %Y',            # '25 October 2006', '25 October, 2006'
 )
 
-class DateField(Field):
+class DateField(CharField):
     default_error_messages = {
         'invalid': _(u'Enter a valid date.'),
     }
@@ -290,7 +296,7 @@
     '%H:%M',        # '14:30'
 )
 
-class TimeField(Field):
+class TimeField(CharField):
     default_error_messages = {
         'invalid': _(u'Enter a valid time.')
     }
@@ -328,7 +334,7 @@
     '%m/%d/%y',              # '10/25/06'
 )
 
-class DateTimeField(Field):
+class DateTimeField(CharField):
     widget = DateTimeInput
     default_error_messages = {
         'invalid': _(u'Enter a valid date/time.'),
@@ -375,7 +381,7 @@
             error_messages = kwargs.get('error_messages') or {}
             error_messages['invalid'] = error_message
             kwargs['error_messages'] = error_messages
-        super(RegexField, self).__init__(max_length, min_length, *args, **kwargs)
+        super(RegexField, self).__init__(max_length=max_length, min_length=min_length, *args, **kwargs)
         if isinstance(regex, basestring):
             regex = re.compile(regex)
         self.regex = regex
@@ -493,10 +499,10 @@
         'invalid_link': _(u'This URL appears to be a broken link.'),
     }
 
-    def __init__(self, max_length=None, min_length=None, verify_exists=False,
+    def __init__(self, max_length=None, min_length=None, length=None, verify_exists=False,
             validator_user_agent=URL_VALIDATOR_USER_AGENT, *args, **kwargs):
-        super(URLField, self).__init__(url_re, max_length, min_length, *args,
-                                       **kwargs)
+        super(URLField, self).__init__(regex=url_re, max_length=max_length, 
+                                       min_length=min_length, length=length, *args, **kwargs)
         self.verify_exists = verify_exists
         self.user_agent = validator_user_agent
 
@@ -557,8 +563,9 @@
 
     def __init__(self, choices=(), required=True, widget=None, label=None,
                  initial=None, help_text=None, *args, **kwargs):
-        super(ChoiceField, self).__init__(required, widget, label, initial,
-                                          help_text, *args, **kwargs)
+        super(ChoiceField, self).__init__(required=required, widget=widget, label=label, 
+                                          initial=initial, help_text=help_text, 
+                                          *args, **kwargs)
         self.choices = choices
 
     def _get_choices(self):
@@ -725,10 +732,10 @@
         if 'error_messages' in kwargs:
             errors.update(kwargs['error_messages'])
         fields = (
-            DateField(error_messages={'invalid': errors['invalid_date']}),
-            TimeField(error_messages={'invalid': errors['invalid_time']}),
+            DateField(error_messages={'invalid': errors['invalid_date']}, max_length=10),
+            TimeField(error_messages={'invalid': errors['invalid_time']}, max_length=8),
         )
-        super(SplitDateTimeField, self).__init__(fields, *args, **kwargs)
+        super(SplitDateTimeField, self).__init__(fields=fields, *args, **kwargs)
 
     def compress(self, data_list):
         if data_list:
@@ -749,4 +756,4 @@
     }
 
     def __init__(self, *args, **kwargs):
-        super(IPAddressField, self).__init__(ipv4_re, *args, **kwargs)
+        super(IPAddressField, self).__init__(regex=ipv4_re, *args, **kwargs)
Index: django/newforms/widgets.py
===================================================================
--- django/newforms/widgets.py	(revision 6860)
+++ django/newforms/widgets.py	(working copy)
@@ -18,22 +18,52 @@
 from util import flatatt
 
 __all__ = (
-    'Widget', 'TextInput', 'PasswordInput',
+    'WidgetDict', 'Widget', 'TextInput', 'PasswordInput',
     'HiddenInput', 'MultipleHiddenInput',
     'FileInput', 'DateTimeInput', 'Textarea', 'CheckboxInput',
     'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect',
     'CheckboxSelectMultiple', 'MultiWidget', 'SplitDateTimeWidget',
 )
 
+
+class WidgetDict(dict):
+    """
+    Tracks most attributes normally - except css classes, which are
+    appended instead of replaced when you set/update the variable.
+
+    If you truly need to override the css class value, just delete and reset it
+    """
+    def _css_class_string(self, value):
+        """
+        Returns string containing combination of all classes
+        """
+        if not value:
+            return self.get('class', '')       
+        my_classes = set(self.get('class', '').split(' '))
+        my_classes.update(value.split(' '))
+        my_classes.discard('')
+        return ' '.join(my_classes)
+
+    def __setitem__(self, key, value):
+        if key == 'class':
+            value = self._css_class_string(value)
+        super(WidgetDict, self).__setitem__(key, value)
+
+    def update(self, new_dict):
+        my_dict = new_dict.copy()
+        if my_dict.has_key('class'):
+            my_dict['class'] = self._css_class_string(my_dict.get('class'))
+        super(WidgetDict, self).update(my_dict)
+
 class Widget(object):
     is_hidden = False          # Determines whether this corresponds to an <input type="hidden">.
     needs_multipart_form = False # Determines does this widget need multipart-encrypted form
 
     def __init__(self, attrs=None):
         if attrs is not None:
-            self.attrs = attrs.copy()
+            self.attrs = WidgetDict(attrs)
         else:
-            self.attrs = {}
+            self.attrs = WidgetDict() 
 
     def __deepcopy__(self, memo):
         obj = copy.copy(self)
@@ -52,7 +82,8 @@
 
     def build_attrs(self, extra_attrs=None, **kwargs):
         "Helper function for building an attribute dictionary."
-        attrs = dict(self.attrs, **kwargs)
+        attrs = WidgetDict(self.attrs)
+        attrs.update(kwargs)
         if extra_attrs:
             attrs.update(extra_attrs)
         return attrs
Index: tests/regressiontests/forms/extra.py
===================================================================
--- tests/regressiontests/forms/extra.py	(revision 6860)
+++ tests/regressiontests/forms/extra.py	(working copy)
@@ -232,25 +232,25 @@
 ...     field1 = ComplexField(widget=w)
 >>> f = ComplexFieldForm()
 >>> print f
-<tr><th><label for="id_field1_0">Field1:</label></th><td><input type="text" name="field1_0" id="id_field1_0" />
-<select multiple="multiple" name="field1_1" id="id_field1_1">
+<tr><th><label for="id_field1_0">Field1:</label></th><td><input id="id_field1_0" type="text" name="field1_0" class="required" />
+<select multiple="multiple" id="id_field1_1" name="field1_1" class="required">
 <option value="J">John</option>
 <option value="P">Paul</option>
 <option value="G">George</option>
 <option value="R">Ringo</option>
 </select>
-<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>
+<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>
 
 >>> f = ComplexFieldForm({'field1_0':'some text','field1_1':['J','P'], 'field1_2_0':'2007-04-25', 'field1_2_1':'06:24:00'})
 >>> print f
-<tr><th><label for="id_field1_0">Field1:</label></th><td><input type="text" name="field1_0" value="some text" id="id_field1_0" />
-<select multiple="multiple" name="field1_1" id="id_field1_1">
+<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" />
+<select multiple="multiple" id="id_field1_1" name="field1_1" class="required">
 <option value="J" selected="selected">John</option>
 <option value="P" selected="selected">Paul</option>
 <option value="G">George</option>
 <option value="R">Ringo</option>
 </select>
-<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>
+<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>
 
 >>> f.cleaned_data
 {'field1': u'some text,JP,2007-04-25 06:24:00'}
@@ -373,9 +373,9 @@
 >>> print f.as_p()
 <p>Name: <input type="text" name="name" maxlength="50" /></p>
 <div class="errorlist"><div class="error">Enter a valid e-mail address.</div></div>
-<p>Email: <input type="text" name="email" value="invalid" /></p>
+<p>Email: <input type="text" class="required" value="invalid" name="email" /></p>
 <div class="errorlist"><div class="error">This field is required.</div></div>
-<p>Comment: <input type="text" name="comment" /></p>
+<p>Comment: <input type="text" class="required" name="comment" /></p>
 
 #################################
 # Test multipart-encoded form #
Index: tests/regressiontests/forms/forms.py
===================================================================
--- tests/regressiontests/forms/forms.py	(revision 6860)
+++ tests/regressiontests/forms/forms.py	(working copy)
@@ -39,11 +39,11 @@
 >>> p.cleaned_data
 {'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
 >>> print p['first_name']
-<input type="text" name="first_name" value="John" id="id_first_name" />
+<input id="id_first_name" type="text" class="required" value="John" name="first_name" />
 >>> print p['last_name']
-<input type="text" name="last_name" value="Lennon" id="id_last_name" />
+<input id="id_last_name" type="text" class="required" value="Lennon" name="last_name" />
 >>> print p['birthday']
-<input type="text" name="birthday" value="1940-10-9" id="id_birthday" />
+<input id="id_birthday" type="text" class="required" value="1940-10-9" name="birthday" />
 >>> print p['nonexistentfield']
 Traceback (most recent call last):
 ...
@@ -51,18 +51,18 @@
 
 >>> for boundfield in p:
 ...     print boundfield
-<input type="text" name="first_name" value="John" id="id_first_name" />
-<input type="text" name="last_name" value="Lennon" id="id_last_name" />
-<input type="text" name="birthday" value="1940-10-9" id="id_birthday" />
+<input id="id_first_name" type="text" class="required" value="John" name="first_name" />
+<input id="id_last_name" type="text" class="required" value="Lennon" name="last_name" />
+<input id="id_birthday" type="text" class="required" value="1940-10-9" name="birthday" />
 >>> for boundfield in p:
 ...     print boundfield.label, boundfield.data
 First name John
 Last name Lennon
 Birthday 1940-10-9
 >>> print p
-<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>
-<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>
-<tr><th><label for="id_birthday">Birthday:</label></th><td><input type="text" name="birthday" value="1940-10-9" id="id_birthday" /></td></tr>
+<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>
+<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>
+<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>
 
 Empty dictionaries are valid, too.
 >>> p = Person({})
@@ -77,24 +77,24 @@
 ...
 AttributeError: 'Person' object has no attribute 'cleaned_data'
 >>> print p
-<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>
-<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>
-<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>
+<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>
+<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>
+<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>
 >>> print p.as_table()
-<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>
-<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>
-<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>
+<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>
+<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>
+<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>
 >>> print p.as_ul()
-<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>
-<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>
-<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>
+<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>
+<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>
+<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>
 >>> print p.as_p()
 <ul class="errorlist"><li>This field is required.</li></ul>
-<p><label for="id_first_name">First name:</label> <input type="text" name="first_name" id="id_first_name" /></p>
+<p><label for="id_first_name">First name:</label> <input id="id_first_name" type="text" class="required" name="first_name" /></p>
 <ul class="errorlist"><li>This field is required.</li></ul>
-<p><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" /></p>
+<p><label for="id_last_name">Last name:</label> <input id="id_last_name" type="text" class="required" name="last_name" /></p>
 <ul class="errorlist"><li>This field is required.</li></ul>
-<p><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" /></p>
+<p><label for="id_birthday">Birthday:</label> <input id="id_birthday" type="text" class="required" name="birthday" /></p>
 
 If you don't pass any values to the Form's __init__(), or if you pass None,
 the Form will be considered unbound and won't do any validation. Form.errors
Index: tests/regressiontests/forms/widgets.py
===================================================================
--- tests/regressiontests/forms/widgets.py	(revision 6860)
+++ tests/regressiontests/forms/widgets.py	(working copy)
@@ -19,6 +19,17 @@
 render itself, given a field name and some data. Widgets don't perform
 validation.
 
+WidgetDict appends css class information instead of overwriting it.
+
+# WidgetDict ##################################################################
+>>> w = WidgetDict({'class': 'test run'})
+>>> w['class'] = 'another'
+>>> print w['class']
+test run another 
+>>> w.update({'class': 'fourth', 'ignore': 'foo'})
+>>> print w['class']
+test another run fourth
+
 # TextInput Widget ############################################################
 
 >>> w = TextInput()
@@ -48,7 +59,7 @@
 'attrs' passed to render() get precedence over those passed to the constructor:
 >>> w = TextInput(attrs={'class': 'pretty'})
 >>> w.render('email', '', attrs={'class': 'special'})
-u'<input type="text" class="special" name="email" />'
+u'<input type="text" class="pretty special" name="email" />'
 
 # PasswordInput Widget ############################################################
 
@@ -74,7 +85,7 @@
 'attrs' passed to render() get precedence over those passed to the constructor:
 >>> w = PasswordInput(attrs={'class': 'pretty'})
 >>> w.render('email', '', attrs={'class': 'special'})
-u'<input type="password" class="special" name="email" />'
+u'<input type="password" class="pretty special" name="email" />'
 
 >>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
 u'<input type="password" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />'
@@ -119,7 +130,7 @@
 'attrs' passed to render() get precedence over those passed to the constructor:
 >>> w = HiddenInput(attrs={'class': 'pretty'})
 >>> w.render('email', '', attrs={'class': 'special'})
-u'<input type="hidden" class="special" name="email" />'
+u'<input type="hidden" class="pretty special" name="email" />'
 
 >>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
 u'<input type="hidden" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />'
@@ -127,7 +138,7 @@
 'attrs' passed to render() get precedence over those passed to the constructor:
 >>> w = HiddenInput(attrs={'class': 'pretty'})
 >>> w.render('email', '', attrs={'class': 'special'})
-u'<input type="hidden" class="special" name="email" />'
+u'<input type="hidden" class="pretty special" name="email" />'
 
 Boolean values are rendered to their string forms ("True" and "False").
 >>> w = HiddenInput()
@@ -166,7 +177,7 @@
 'attrs' passed to render() get precedence over those passed to the constructor:
 >>> w = MultipleHiddenInput(attrs={'class': 'pretty'})
 >>> w.render('email', ['foo@example.com'], attrs={'class': 'special'})
-u'<input type="hidden" class="special" value="foo@example.com" name="email" />'
+u'<input type="hidden" class="pretty special" value="foo@example.com" name="email" />'
 
 >>> w.render('email', ['ŠĐĆŽćžšđ'], attrs={'class': 'fun'})
 u'<input type="hidden" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />'
@@ -174,7 +185,7 @@
 'attrs' passed to render() get precedence over those passed to the constructor:
 >>> w = MultipleHiddenInput(attrs={'class': 'pretty'})
 >>> w.render('email', ['foo@example.com'], attrs={'class': 'special'})
-u'<input type="hidden" class="special" value="foo@example.com" name="email" />'
+u'<input type="hidden" class="pretty special" value="foo@example.com" name="email" />'
 
 # FileInput Widget ############################################################
 
@@ -228,7 +239,7 @@
 'attrs' passed to render() get precedence over those passed to the constructor:
 >>> w = Textarea(attrs={'class': 'pretty'})
 >>> w.render('msg', '', attrs={'class': 'special'})
-u'<textarea rows="10" cols="40" name="msg" class="special"></textarea>'
+u'<textarea rows="10" cols="40" name="msg" class="pretty special"></textarea>'
 
 >>> w.render('msg', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
 u'<textarea rows="10" cols="40" name="msg" class="fun">\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111</textarea>'
@@ -261,7 +272,7 @@
 'attrs' passed to render() get precedence over those passed to the constructor:
 >>> w = CheckboxInput(attrs={'class': 'pretty'})
 >>> w.render('is_cool', '', attrs={'class': 'special'})
-u'<input type="checkbox" class="special" name="is_cool" />'
+u'<input type="checkbox" class="pretty special" name="is_cool" />'
 
 You can pass 'check_test' to the constructor. This is a callable that takes the
 value and returns True if the box should be checked.
