Django

Code

Changeset 4159

Show
Ignore:
Timestamp:
12/04/06 15:12:29 (2 years ago)
Author:
jpellerin
Message:

[multi-db] Merged trunk to [4158]. Some tests still failing.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/multiple-db-support/AUTHORS

    r4158 r4159  
    152152    sopel 
    153153    Thomas Steinacher <tom@eggdrop.ch> 
     154    nowell strite 
    154155    Radek Švarz <http://www.svarz.cz/translate/> 
    155156    Swaroop C H <http://www.swaroopch.info> 
  • django/branches/multiple-db-support/django/conf/project_template/urls.py

    r2809 r4159  
    33urlpatterns = patterns('', 
    44    # Example: 
    5     # (r'^{{ project_name }}/', include('{{ project_name }}.apps.foo.urls.foo')), 
     5    # (r'^{{ project_name }}/', include('{{ project_name }}.foo.urls')), 
    66 
    77    # Uncomment this for admin: 
  • django/branches/multiple-db-support/django/contrib/sitemaps/templates/sitemap_index.xml

    r4158 r4159  
    11<?xml version="1.0" encoding="UTF-8"?> 
    2 <sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemapindex/0.9"> 
     2<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> 
    33{% for location in sitemaps %}<sitemap><loc>{{ location|escape }}</loc></sitemap>{% endfor %} 
    44</sitemapindex> 
  • django/branches/multiple-db-support/django/core/handlers/base.py

    r4156 r4159  
    8585            # Complain if the view returned None (a common error). 
    8686            if response is None: 
    87                 raise ValueError, "The view %s.%s didn't return an HttpResponse object." % (callback.__module__, callback.func_name) 
     87                try: 
     88                    view_name = callback.func_name # If it's a function 
     89                except AttributeError: 
     90                    view_name = callback.__class__.__name__ + '.__call__' # If it's a class 
     91                raise ValueError, "The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name) 
    8892 
    8993            return response 
  • django/branches/multiple-db-support/django/core/handlers/wsgi.py

    r4158 r4159  
    6363    """ 
    6464    if not size: 
    65         return copyfileobj(fsrc, fdst, length) 
     65        return 
    6666    while size > 0: 
    6767        buf = fsrc.read(min(length, size)) 
     
    158158        except AttributeError: 
    159159            buf = StringIO() 
    160             # CONTENT_LENGTH might be absent if POST doesn't have content at all (lighttpd) 
    161             content_length = int(self.environ.get('CONTENT_LENGTH', 0)) 
     160            try: 
     161                # CONTENT_LENGTH might be absent if POST doesn't have content at all (lighttpd) 
     162                content_length = int(self.environ.get('CONTENT_LENGTH', 0)) 
     163            except ValueError: # if CONTENT_LENGTH was empty string or not an integer 
     164                content_length = 0 
    162165            safe_copyfileobj(self.environ['wsgi.input'], buf, size=content_length) 
    163166            self._raw_post_data = buf.getvalue() 
  • django/branches/multiple-db-support/django/db/models/fields/__init__.py

    r4157 r4159  
    458458    def get_db_prep_save(self, value): 
    459459        # Casts dates into string format for entry into database. 
    460         if isinstance(value, datetime.datetime): 
    461             value = value.date().strftime('%Y-%m-%d') 
    462         elif isinstance(value, datetime.date): 
     460        if value is not None: 
    463461            value = value.strftime('%Y-%m-%d') 
    464462        return Field.get_db_prep_save(self, value) 
     
    490488    def pre_save(self, model_instance, add): 
    491489        value = super(DateField, self).pre_save(model_instance, add) 
    492         if isinstance(value, datetime.datetime)
     490        if value is not None
    493491            # MySQL will throw a warning if microseconds are given, because it 
    494492            # doesn't support microseconds. 
     
    502500        if value is not None: 
    503501            value = str(value) 
    504         elif isinstance(value, datetime.date): 
    505             # MySQL will throw a warning if microseconds are given, because it 
    506             # doesn't support microseconds. 
    507             if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'): 
    508                 value = datetime.datetime(value.year, value.month, value.day, microsecond=0) 
    509             value = str(value) 
    510              
    511502        return Field.get_db_prep_save(self, value) 
    512503 
  • django/branches/multiple-db-support/django/http/__init__.py

    r4139 r4159  
    209209            self.cookies[key]['path'] = path 
    210210        if domain is not None: 
    211             self.cookies[key]['domain'] = path 
     211            self.cookies[key]['domain'] = domain 
    212212        self.cookies[key]['expires'] = 0 
    213213        self.cookies[key]['max-age'] = 0 
  • django/branches/multiple-db-support/django/newforms/fields.py

    r4158 r4159  
    7777        """ 
    7878        super(IntegerField, self).clean(value) 
     79        if not self.required and value in EMPTY_VALUES: 
     80            return u'' 
    7981        try: 
    8082            return int(value) 
     
    171173        if value in EMPTY_VALUES: value = u'' 
    172174        value = smart_unicode(value) 
     175        if not self.required and value == u'': 
     176            return value 
    173177        if not self.regex.search(value): 
    174178            raise ValidationError(self.error_message) 
     
    247251        if value in EMPTY_VALUES: value = u'' 
    248252        value = smart_unicode(value) 
     253        if not self.required and value == u'': 
     254            return value 
    249255        valid_values = set([str(k) for k, v in self.choices]) 
    250256        if value not in valid_values: 
     
    260266        Validates that the input is a list or tuple. 
    261267        """ 
     268        if self.required and not value: 
     269            raise ValidationError(u'This field is required.') 
     270        elif not self.required and not value: 
     271            return [] 
    262272        if not isinstance(value, (list, tuple)): 
    263273            raise ValidationError(u'Enter a list of values.') 
    264         if self.required and not value: 
    265             raise ValidationError(u'This field is required.') 
    266274        new_value = [] 
    267275        for val in value: 
     
    278286    def __init__(self, fields=(), required=True, widget=None): 
    279287        Field.__init__(self, required, widget) 
     288        # Set 'required' to False on the individual fields, because the 
     289        # required validation will be handled by ComboField, not by those 
     290        # individual fields. 
     291        for f in fields: 
     292            f.required = False 
    280293        self.fields = fields 
    281294 
  • django/branches/multiple-db-support/django/newforms/forms.py

    r4158 r4159  
    44 
    55from django.utils.datastructures import SortedDict 
     6from django.utils.html import escape 
    67from fields import Field 
    7 from widgets import TextInput, Textarea 
     8from widgets import TextInput, Textarea, HiddenInput 
    89from util import ErrorDict, ErrorList, ValidationError 
    910 
     
    3738 
    3839    def __init__(self, data=None, auto_id=False): # TODO: prefix stuff 
     40        self.ignore_errors = data is None 
    3941        self.data = data or {} 
    4042        self.auto_id = auto_id 
     
    5759        return BoundField(self, field, name) 
    5860 
    59     def clean(self): 
    60         if self.__errors is None: 
    61             self.full_clean() 
    62         return self.clean_data 
    63  
    64     def errors(self): 
     61    def _errors(self): 
    6562        "Returns an ErrorDict for self.data" 
    6663        if self.__errors is None: 
    6764            self.full_clean() 
    6865        return self.__errors 
     66    errors = property(_errors) 
    6967 
    7068    def is_valid(self): 
    7169        """ 
    72         Returns True if the form has no errors. Otherwise, False. This exists 
    73         solely for convenience, so client code can use positive logic rather 
    74         than confusing negative logic ("if not form.errors()"). 
    75         """ 
    76         return not bool(self.errors()) 
     70        Returns True if the form has no errors. Otherwise, False. If errors are 
     71        being ignored, returns False. 
     72        """ 
     73        return not self.ignore_errors and not bool(self.errors) 
    7774 
    7875    def as_table(self): 
    7976        "Returns this form rendered as HTML <tr>s -- excluding the <table></table>." 
    80         return u'\n'.join(['<tr><td>%s:</td><td>%s</td></tr>' % (pretty_name(name), BoundField(self, field, name)) for name, field in self.fields.items()]) 
     77        output = [] 
     78        if self.errors.get(NON_FIELD_ERRORS): 
     79            # Errors not corresponding to a particular field are displayed at the top. 
     80            output.append(u'<tr><td colspan="2">%s</td></tr>' % self.non_field_errors()) 
     81        for name, field in self.fields.items(): 
     82            bf = BoundField(self, field, name) 
     83            if bf.is_hidden: 
     84                if bf.errors: 
     85                    new_errors = ErrorList(['(Hidden field %s) %s' % (name, e) for e in bf.errors]) 
     86                    output.append(u'<tr><td colspan="2">%s</td></tr>' % new_errors) 
     87                output.append(str(bf)) 
     88            else: 
     89                if bf.errors: 
     90                    output.append(u'<tr><td colspan="2">%s</td></tr>' % bf.errors) 
     91                output.append(u'<tr><td>%s</td><td>%s</td></tr>' % (bf.label_tag(escape(bf.verbose_name+':')), bf)) 
     92        return u'\n'.join(output) 
    8193 
    8294    def as_ul(self): 
    8395        "Returns this form rendered as HTML <li>s -- excluding the <ul></ul>." 
    84         return u'\n'.join(['<li>%s: %s</li>' % (pretty_name(name), BoundField(self, field, name)) for name, field in self.fields.items()]) 
    85  
    86     def as_table_with_errors(self): 
    87         "Returns this form rendered as HTML <tr>s, with errors." 
    8896        output = [] 
    89         if self.errors().get(NON_FIELD_ERRORS): 
     97        if self.errors.get(NON_FIELD_ERRORS): 
    9098            # Errors not corresponding to a particular field are displayed at the top. 
    91             output.append('<tr><td colspan="2"><ul>%s</ul></td></tr>' % '\n'.join(['<li>%s</li>' % e for e in self.errors()[NON_FIELD_ERRORS]])) 
     99            output.append(u'<li>%s</li>' % self.non_field_errors()) 
    92100        for name, field in self.fields.items(): 
    93101            bf = BoundField(self, field, name) 
    94             if bf.errors: 
    95                 output.append('<tr><td colspan="2"><ul>%s</ul></td></tr>' % '\n'.join(['<li>%s</li>' % e for e in bf.errors])) 
    96             output.append('<tr><td>%s:</td><td>%s</td></tr>' % (pretty_name(name), bf)) 
     102            if bf.is_hidden: 
     103                if bf.errors: 
     104                    new_errors = ErrorList(['(Hidden field %s) %s' % (name, e) for e in bf.errors]) 
     105                    output.append(u'<li>%s</li>' % new_errors) 
     106                output.append(str(bf)) 
     107            else: 
     108                output.append(u'<li>%s%s %s</li>' % (bf.errors, bf.label_tag(escape(bf.verbose_name+':')), bf)) 
    97109        return u'\n'.join(output) 
    98110 
    99     def as_ul_with_errors(self): 
    100         "Returns this form rendered as HTML <li>s, with errors." 
    101         output = [] 
    102         if self.errors().get(NON_FIELD_ERRORS): 
    103             # Errors not corresponding to a particular field are displayed at the top. 
    104             output.append('<li><ul>%s</ul></li>' % '\n'.join(['<li>%s</li>' % e for e in self.errors()[NON_FIELD_ERRORS]])) 
    105         for name, field in self.fields.items(): 
    106             bf = BoundField(self, field, name) 
    107             line = '<li>' 
    108             if bf.errors: 
    109                 line += '<ul>%s</ul>' % '\n'.join(['<li>%s</li>' % e for e in bf.errors]) 
    110             line += '%s: %s</li>' % (pretty_name(name), bf) 
    111             output.append(line) 
    112         return u'\n'.join(output) 
     111    def non_field_errors(self): 
     112        """ 
     113        Returns an ErrorList of errors that aren't associated with a particular 
     114        field -- i.e., from Form.clean(). Returns an empty ErrorList if there 
     115        are none. 
     116        """ 
     117        return self.errors.get(NON_FIELD_ERRORS, ErrorList()) 
    113118 
    114119    def full_clean(self): 
     
    118123        self.clean_data = {} 
    119124        errors = ErrorDict() 
    120         for name, field in self.fields.items(): 
    121             value = self.data.get(name, None) 
     125        if self.ignore_errors: # Stop further processing. 
     126            self.__errors = errors 
     127            return 
     128        for name, field in self.fields.items(): 
     129            # value_from_datadict() gets the data from the dictionary. 
     130            # Each widget type knows how to retrieve its own data, because some 
     131            # widgets split data over several HTML fields. 
     132            value = field.widget.value_from_datadict(self.data, name) 
    122133            try: 
    123134                value = field.clean(value) 
     
    139150        """ 
    140151        Hook for doing any extra form-wide cleaning after Field.clean() been 
    141         called on every field. 
     152        called on every field. Any ValidationError raised by this method will 
     153        not be associated with a particular field; it will have a special-case 
     154        association with the field named '__all__'. 
    142155        """ 
    143156        return self.clean_data 
     
    154167        # Use the 'widget' attribute on the field to determine which type 
    155168        # of HTML widget to use. 
    156         return self.as_widget(self._field.widget) 
     169        value = self.as_widget(self._field.widget) 
     170        if not isinstance(value, basestring): 
     171            # Some Widget render() methods -- notably RadioSelect -- return a 
     172            # "special" object rather than a string. Call the __str__() on that 
     173            # object to get its rendered value. 
     174            value = value.__str__() 
     175        return value 
    157176 
    158177    def _errors(self): 
     
    162181        """ 
    163182        try: 
    164             return self._form.errors()[self._name] 
     183            return self._form.errors[self._name] 
    165184        except KeyError: 
    166185            return ErrorList() 
     
    170189        attrs = attrs or {} 
    171190        auto_id = self.auto_id 
    172         if not attrs.has_key('id') and not widget.attrs.has_key('id') and auto_id
     191        if auto_id and not attrs.has_key('id') and not widget.attrs.has_key('id')
    173192            attrs['id'] = auto_id 
    174         return widget.render(self._name, self._form.data.get(self._name, None), attrs=attrs) 
     193        return widget.render(self._name, self.data, attrs=attrs) 
    175194 
    176195    def as_text(self, attrs=None): 
     
    183202        "Returns a string of HTML for representing this as a <textarea>." 
    184203        return self.as_widget(Textarea(), attrs) 
     204 
     205    def as_hidden(self, attrs=None): 
     206        """ 
     207        Returns a string of HTML for representing this as an <input type="hidden">. 
     208        """ 
     209        return self.as_widget(HiddenInput(), attrs) 
     210 
     211    def _data(self): 
     212        "Returns the data for this BoundField, or None if it wasn't given." 
     213        return self._form.data.get(self._name, None) 
     214    data = property(_data) 
     215 
     216    def _verbose_name(self): 
     217        return pretty_name(self._name) 
     218    verbose_name = property(_verbose_name) 
     219 
     220    def label_tag(self, contents=None): 
     221        """ 
     222        Wraps the given contents in a <label>, if the field has an ID attribute. 
     223        Does not HTML-escape the contents. If contents aren't given, uses the 
     224        field's HTML-escaped verbose_name. 
     225        """ 
     226        contents = contents or escape(self.verbose_name) 
     227        widget = self._field.widget 
     228        id_ = widget.attrs.get('id') or self.auto_id 
     229        if id_: 
     230            contents = '<label for="%s">%s</label>' % (widget.id_for_label(id_), contents) 
     231        return contents 
     232 
     233    def _is_hidden(self): 
     234        "Returns True if this BoundField's widget is hidden." 
     235        return self._field.widget.is_hidden 
     236    is_hidden = property(_is_hidden) 
    185237 
    186238    def _auto_id(self): 
  • django/branches/multiple-db-support/django/newforms/__init__.py

    r4156 r4159  
    1515from fields import * 
    1616from forms import Form 
    17  
    18 ########################## 
    19 # DATABASE API SHORTCUTS # 
    20 ########################## 
    21  
    22 def form_for_model(model): 
    23     "Returns a Form instance for the given Django model class." 
    24     raise NotImplementedError 
    25  
    26 def form_for_fields(field_list): 
    27     "Returns a Form instance for the given list of Django database field instances." 
    28     raise NotImplementedError 
     17from models import * 
  • django/branches/multiple-db-support/django/newforms/widgets.py

    r4158 r4159  
    66    'Widget', 'TextInput', 'PasswordInput', 'HiddenInput', 'FileInput', 
    77    'Textarea', 'CheckboxInput', 
    8     'Select', 'SelectMultiple', 'RadioSelect', 
     8    'Select', 'SelectMultiple', 'RadioSelect', 'CheckboxSelectMultiple', 
    99) 
    1010 
     
    2424class Widget(object): 
    2525    requires_data_list = False # Determines whether render()'s 'value' argument should be a list. 
     26    is_hidden = False          # Determines whether this corresponds to an <input type="hidden">. 
     27 
    2628    def __init__(self, attrs=None): 
    2729        self.attrs = attrs or {} 
     
    3133 
    3234    def build_attrs(self, extra_attrs=None, **kwargs): 
     35        "Helper function for building an attribute dictionary." 
    3336        attrs = dict(self.attrs, **kwargs) 
    3437        if extra_attrs: 
    3538            attrs.update(extra_attrs) 
    3639        return attrs 
     40 
     41    def value_from_datadict(self, data, name): 
     42        """ 
     43        Given a dictionary of data and this widget's name, returns the value 
     44        of this widget. Returns None if it's not provided. 
     45        """ 
     46        return data.get(name, None) 
     47 
     48    def id_for_label(self, id_): 
     49        """ 
     50        Returns the HTML ID attribute of this Widget for use by a <label>, 
     51        given the ID of the field. Returns None if no ID is available. 
     52 
     53        This hook is necessary because some widgets have multiple HTML 
     54        elements and, thus, multiple IDs. In that case, this method should 
     55        return an ID value that corresponds to the first ID in the widget's 
     56        tags. 
     57        """ 
     58        return id_ 
     59    id_for_label = classmethod(id_for_label) 
    3760 
    3861class Input(Widget): 
     
    5679class HiddenInput(Input): 
    5780    input_type = 'hidden' 
     81    is_hidden = True 
    5882 
    5983class FileInput(Input): 
     
    6892 
    6993class CheckboxInput(Widget): 
     94    def __init__(self, attrs=None, check_test=bool): 
     95        # check_test is a callable that takes a value and returns True 
     96        # if the checkbox should be checked for that value. 
     97        self.attrs = attrs or {} 
     98        self.check_test = check_test 
     99 
    70100    def render(self, name, value, attrs=None): 
    71101        final_attrs = self.build_attrs(attrs, type='checkbox', name=name) 
    72         if value: final_attrs['checked'] = 'checked' 
     102        try: 
     103            result = self.check_test(value) 
     104        except: # Silently catch exceptions 
     105            result = False 
     106        if result: 
     107            final_attrs['checked'] = 'checked' 
     108        if value not in ('', True, False, None): 
     109            final_attrs['value'] = smart_unicode(value) # Only add the 'value' attribute if a value is non-empty. 
    73110        return u'<input%s />' % flatatt(final_attrs) 
    74111 
     
    112149class RadioInput(object): 
    113150    "An object used by RadioFieldRenderer that represents a single <input type='radio'>." 
    114     def __init__(self, name, value, attrs, choice): 
     151    def __init__(self, name, value, attrs, choice, index): 
    115152        self.name, self.value = name, value 
    116         self.attrs = attrs or {} 
     153        self.attrs = attrs 
    117154        self.choice_value, self.choice_label = choice 
     155        self.index = index 
    118156 
    119157    def __str__(self): 
     
    124162 
    125163    def tag(self): 
     164        if self.attrs.has_key('id'): 
     165            self.attrs['id'] = '%s_%s' % (self.attrs['id'], self.index) 
    126166        final_attrs = dict(self.attrs, type='radio', name=self.name, value=self.choice_value) 
    127167        if self.is_checked(): 
     
    136176 
    137177    def __iter__(self): 
    138         for choice in self.choices
    139             yield RadioInput(self.name, self.value, self.attrs, choice
     178        for i, choice in enumerate(self.choices)
     179            yield RadioInput(self.name, self.value, self.attrs.copy(), choice, i
    140180 
    141181    def __str__(self): 
     
    148188        if value is None: value = '' 
    149189        str_value = smart_unicode(value) # Normalize to string. 
     190        attrs = attrs or {} 
    150191        return RadioFieldRenderer(name, str_value, attrs, list(chain(self.choices, choices))) 
    151192 
    152 class CheckboxSelectMultiple(Widget): 
    153     pass 
     193    def id_for_label(self, id_): 
     194        # RadioSelect is represented by multiple <input type="radio"> fields, 
     195        # each of which has a distinct ID. The IDs are made distinct by a "_X" 
     196        # suffix, where X is the zero-based index of the radio field. Thus, 
     197        # the label for a RadioSelect should reference the first one ('_0'). 
     198        if id_: 
     199            id_ += '_0' 
     200        return id_ 
     201    id_for_label = classmethod(id_for_label) 
     202 
     203class CheckboxSelectMultiple(SelectMultiple): 
     204    def render(self, name, value, attrs=None, choices=()): 
     205        if value is None: value = [] 
     206        final_attrs = self.build_attrs(attrs, name=name) 
     207        output = [u'<ul>'] 
     208        str_values = set([smart_unicode(v) for v in value]) # Normalize to strings. 
     209        cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values) 
     210        for option_value, option_label in chain(self.choices, choices): 
     211            option_value = smart_unicode(option_value) 
     212            rendered_cb = cb.render(name, option_value) 
     213            output.append(u'<li><label>%s %s</label></li>' % (rendered_cb, escape(smart_unicode(option_label)))) 
     214        output.append(u'</ul>') 
     215        return u'\n'.join(output) 
     216 
     217    def id_for_label(self, id_): 
     218        # See the comment for RadioSelect.id_for_label() 
     219        if id_: 
     220            id_ += '_0' 
     221        return id_ 
     222    id_for_label = classmethod(id_for_label) 
  • django/branches/multiple-db-support/django/views/generic/list_detail.py

    r3071 r4159  
    8585        mimetype=None): 
    8686    """ 
    87     Generic list of objects
     87    Generic detail of an object
    8888 
    8989    Templates: ``<app_label>/<model_name>_detail.html`` 
  • django/branches/multiple-db-support/docs/sessions.txt

    r3581 r4159  
    142142 
    143143    def login(request): 
    144         if request.POST
     144        if request.method == 'POST'
    145145            if request.session.test_cookie_worked(): 
    146146                request.session.delete_test_cookie() 
  • django/branches/multiple-db-support/docs/testing.txt

    r4158 r4159  
    134134 
    135135For developers new to testing, however, this choice can seem 
    136 confusing, so here are a few key differences to help you decide weather 
     136confusing, so here are a few key differences to help you decide whether 
    137137doctests or unit tests are right for you. 
    138138 
  • django/branches/multiple-db-support/setup.py

    r4155 r4159  
    1212# an easy way to do this. 
    1313packages, data_files = [], [] 
    14 root_dir = os.path.join(os.path.dirname(__file__), 'django') 
    15 for dirpath, dirnames, filenames in os.walk(root_dir): 
     14root_dir = os.path.dirname(__file__) 
     15len_root_dir = len(root_dir) 
     16django_dir = os.path.join(root_dir, 'django') 
     17 
     18for dirpath, dirnames, filenames in os.walk(django_dir): 
    1619    # Ignore dirnames that start with '.' 
    1720    for i, dirname in enumerate(dirnames): 
    1821        if dirname.startswith('.'): del dirnames[i] 
    1922    if '__init__.py' in filenames: 
    20         packages.append(dirpath.replace('/', '.')) 
     23        package = dirpath[len_root_dir:].lstrip('/').replace('/', '.') 
     24        packages.append(package) 
    2125    else: 
    2226        data_files.append((dirpath, [os.path.join(dirpath, f) for f in filenames])) 
  • django/branches/multiple-db-support/tests/regressiontests/forms/tests.py

    r4158 r4159  
    44>>> import datetime 
    55>>> import re 
     6 
     7########### 
     8# Widgets # 
     9########### 
     10 
     11Each Widget class corresponds to an HTML form widget. A Widget knows how to 
     12render itself, given a field name and some data. Widgets don't perform 
     13validation. 
    614 
    715# TextInput Widget ############################################################ 
     
    157165>>> w.render('is_cool', '') 
    158166u'<input type="checkbox" name="is_cool" />' 
     167>>> w.render('is_cool', None) 
     168u'<input type="checkbox" name="is_cool" />' 
    159169>>> w.render('is_cool', False) 
    160170u'<input type="checkbox" name="is_cool" />' 
    161171>>> w.render('is_cool', True) 
    162172u'<input checked="checked" type="checkbox" name="is_cool" />' 
     173 
     174Using any value that's not in ('', None, False, True) will check the checkbox 
     175and set the 'value' attribute. 
     176>>> w.render('is_cool', 'foo') 
     177u'<input checked="checked" type="checkbox" name="is_cool" value="foo" />' 
     178 
    163179>>> w.render('is_cool', False, attrs={'class': 'pretty'}) 
    164180u'<input type="checkbox" name="is_cool" class="pretty" />' 
     
    173189>>> w.render('is_cool', '', attrs={'class': 'special'}) 
    174190u'<input type="checkbox" class="special" name="is_cool" />' 
     191 
     192You can pass 'check_test' to the constructor. This is a callable that takes the 
     193value and returns True if the box should be checked. 
     194>>> w = CheckboxInput(check_test=lambda value: value.startswith('hello')) 
     195>>> w.render('greeting', '') 
     196u'<input type="checkbox" name="greeting" />' 
     197>>> w.render('greeting', 'hello') 
     198u'<input checked="checked" type="checkbox" name="greeting" value="hello" />' 
     199>>> w.render('greeting', 'hello there') 
     200u'<input checked="checked" type="checkbox" name="greeting" value="hello there" />' 
     201>>> w.render('greeting', 'hello & goodbye') 
     202u'<input checked="checked" type="checkbox" name="greeting" value="hello &amp; goodbye" />' 
     203 
     204A subtlety: If the 'check_test' argument cannot handle a value and raises any 
     205exception during its __call__, then the exception will be swallowed and the box 
     206will not be checked. In this example, the 'check_test' assumes the value has a 
     207startswith() method, which fails for the values True, False and None. 
     208>>> w.render('greeting', True) 
     209u'<input type="checkbox" name="greeting" />' 
     210>>> w.render('greeting', False) 
     211u'<input type="checkbox" name="greeting" />' 
     212>>> w.render('greeting', None) 
     213u'<input type="checkbox" name="greeting" />' 
    175214 
    176215# Select Widget ############################################################### 
     
    476515beatle J R Ringo False 
    477516 
     517# CheckboxSelectMultiple Widget ############################################### 
     518 
     519>>> w = CheckboxSelectMultiple() 
     520>>> print w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 
     521<ul> 
     522<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li> 
     523<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li> 
     524<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li> 
     525<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li> 
     526</ul> 
     527>>> print w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 
     528<ul> 
     529<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li> 
     530<li><label><input checked="checked" type="checkbox" name="beatles" value="P" /> Paul</label></li> 
     531<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li> 
     532<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li> 
     533</ul> 
     534>>> print w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 
     535<ul> 
     536<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li> 
     537<li><label><input checked="checked" type="checkbox" name="beatles" value="P" /> Paul</label></li> 
     538<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li> 
     539<li><label><input checked="checked" type="checkbox" name="beatles" value="R" /> Ringo</label></li> 
     540</ul> 
     541 
     542If the value is None, none of the options are selected: 
     543>>> print w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 
     544<ul> 
     545<li><label><input type="checkbox" name="beatles" value="J" /> John</label></li> 
     546<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li> 
     547<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li> 
     548<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li> 
     549</ul> 
     550 
     551If the value corresponds to a label (but not to an option value), none of the options are selected: 
     552>>> print w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 
     553<ul> 
     554<li><label><input type="checkbox" name="beatles" value="J" /> John</label></li> 
     555<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li> 
     556<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li> 
     557<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li> 
     558</ul> 
     559 
     560If multiple values are given, but some of them are not valid, the valid ones are selected: 
     561>>> print w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 
     562<ul> 
     563<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li> 
     564<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li> 
     565<li><label><input checked="checked" type="checkbox" name="beatles" value="G" /> George</label></li> 
     566<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li> 
     567</ul> 
     568 
     569The value is compared to its str(): 
     570>>> print w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')]) 
     571<ul> 
     572<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li> 
     573<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li> 
     574<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li> 
     575</ul> 
     576>>> print w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)]) 
     577<ul> 
     578<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li> 
     579<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li> 
     580<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li> 
     581</ul> 
     582>>> print w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)]) 
     583<ul> 
     584<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li> 
     585<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li> 
     586<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li> 
     587</ul> 
     588 
     589The 'choices' argument can be any iterable: 
     590>>> def get_choices(): 
     591...     for i in range(5): 
     592...         yield (i, i) 
     593>>> print w.render('nums', [2], choices=get_choices()) 
     594<ul> 
     595<li><label><input type="checkbox" name="nums" value="0" /> 0</label></li> 
     596<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li> 
     597<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li> 
     598<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li> 
     599<li><label><input type="checkbox" name="nums" value="4" /> 4</label></li> 
     600</ul> 
     601 
     602You can also pass 'choices' to the constructor: 
     603>>> w = CheckboxSelectMultiple(choices=[(1, 1), (2, 2), (3, 3)]) 
     604>>> print w.render('nums', [2]) 
     605<ul> 
     606<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li> 
     607<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li> 
     608<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li> 
     609</ul> 
     610 
     611If 'choices' is passed to both the constructor and render(), then they'll both be in the output: 
     612>>> print w.render('nums', [2], choices=[(4, 4), (5, 5)]) 
     613<ul> 
     614<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li> 
     615<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li> 
     616<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li> 
     617<li><label><input type="checkbox" name="nums" value="4" /> 4</label></li> 
     618<li><label><input type="checkbox" name="nums" value="5" /> 5</label></li> 
     619</ul> 
     620 
     621>>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]) 
     622u'<ul>\n<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>\n<li><label><input type="checkbox" name="nums" value="2" /> 2</label></li>\n<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>\n<li><label><input checked="checked" type="checkbox" name="nums" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /> \u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</label></li>\n<li><label><input type="checkbox" name="nums" value="\u0107\u017e\u0161\u0111" /> abc\u0107\u017e\u0161\u0111</label></li>\n</ul>' 
     623 
     624########## 
     625# Fields # 
     626########## 
     627 
     628Each Field class does some sort of validation. Each Field has a clean() method, 
     629which either raises django.newforms.ValidationError or returns the "clean" 
     630data -- usually a Unicode object, but, in some rare cases, a list. 
     631 
     632Each Field's __init__() takes at least these parameters: 
     633    required -- Boolean that specifies whether the field is required. 
     634                True by default. 
     635    widget -- A Widget class, or instance of a Widget class, that should be 
     636              used for this Field when displaying it. Each Field has a default 
     637              Widget that it'll use if you don't specify this. In most cases, 
     638              the default widget is TextInput. 
     639 
     640Other than that, the Field subclasses have class-specific options for 
     641__init__(). For example, CharField has a max_length option. 
     642 
    478643# CharField ################################################################### 
     644 
     645>>> f = CharField() 
     646>>> f.clean(1) 
     647u'1' 
     648>>> f.clean('hello') 
     649u'hello' 
     650>>> f.clean(None) 
     651Traceback (most recent call last): 
     652... 
     653ValidationError: [u'This field is required.'] 
     654>>> f.clean('') 
     655Traceback (most recent call last): 
     656... 
     657ValidationError: [u'This field is required.'] 
     658>>> f.clean([1, 2, 3]) 
     659u'[1, 2, 3]' 
    479660 
    480661>>> f = CharField(required=False) 
     
    485666>>> f.clean(None) 
    486667u'' 
     668>>> f.clean('') 
     669u'' 
    487670>>> f.clean([1, 2, 3]) 
    488671u'[1, 2, 3]' 
     
    490673CharField accepts an optional max_length parameter: 
    491674>>> f = CharField(max_length=10, required=False) 
    492 >>> f.clean('') 
    493 u'' 
    494675>>> f.clean('12345') 
    495676u'12345' 
     
    519700 
    520701>>> f = IntegerField() 
     702>>> f.clean('') 
     703Traceback (most recent call last): 
     704... 
     705ValidationError: [u'This field is required.'] 
     706>>> f.clean(None) 
     707Traceback (most recent call last): 
     708... 
     709ValidationError: [u'This field is required.'] 
     710>>> f.clean('1') 
     7111