Ticket #2723: booleanwidget_radio_with_tests.diff

File booleanwidget_radio_with_tests.diff, 9.4 KB (added by Remco Wendt, 16 years ago)

Improved patch with tests

  • django/contrib/admin/options.py

     
    161161            kwargs['widget'] = widgets.AdminTimeWidget
    162162            return db_field.formfield(**kwargs)
    163163
     164        # For BooleanFields, use a special widget with a custom css class.
     165        if isinstance(db_field, models.BooleanField):
     166            kwargs['widget'] = widgets.AdminBooleanSelectWidget
     167            return db_field.formfield(**kwargs)
     168
    164169        # For FileFields and ImageFields add a link to the current file.
    165170        if isinstance(db_field, models.ImageField) or isinstance(db_field, models.FileField):
    166171            kwargs['widget'] = widgets.AdminFileWidget
  • django/contrib/admin/widgets.py

     
    77from django.utils.text import capfirst, truncate_words
    88from django.utils.translation import ugettext as _
    99from django.utils.safestring import mark_safe
     10from django.utils.encoding import force_unicode
    1011from django.conf import settings
    1112
    1213class FilteredSelectMultiple(forms.SelectMultiple):
     
    4647
    4748    def __init__(self, attrs={}):
    4849        super(AdminTimeWidget, self).__init__(attrs={'class': 'vTimeField', 'size': '8'})
     50
     51class AdminBooleanSelectRenderer(forms.widgets.RadioFieldRenderer):
     52    def render(self):
     53        """Outputs a <ul> for this set of radio fields."""
     54        return mark_safe(u'<ul class="plainlist">\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>'
     55                % force_unicode(w) for w in self]))
     56
     57class AdminBooleanSelectWidget(forms.RadioSelect):
     58    renderer = AdminBooleanSelectRenderer
    4959   
     60    def __init__(self, attrs=None):
     61        choices = ((u'1', _('Yes')), (u'2', _('No')))
     62        super(AdminBooleanSelectWidget, self).__init__(attrs, choices)
     63
     64    def render(self, name, value, attrs=None, choices=()):
     65        try:
     66            value = {True: u'1', False: u'2', u'1': u'1', u'2': u'2'}[value]
     67        except KeyError:
     68            value = u'2'
     69        return super(AdminBooleanSelectWidget, self).render(name, value, attrs, choices)
     70
     71    def value_from_datadict(self, data, files, name):
     72        value = data.get(name, None)
     73        return {u'1': True, u'2': False, True: True, False: False}.get(value, None)
     74   
    5075class AdminSplitDateTime(forms.SplitDateTimeWidget):
    5176    """
    5277    A SplitDateTime Widget that has some admin-specific styling.
  • tests/regressiontests/admin_widgets/models.py

     
    2828>>> from django.contrib.admin.widgets import FilteredSelectMultiple, AdminSplitDateTime
    2929>>> from django.contrib.admin.widgets import AdminFileWidget, ForeignKeyRawIdWidget, ManyToManyRawIdWidget
    3030>>> from django.contrib.admin.widgets import RelatedFieldWidgetWrapper
     31>>> from django.contrib.admin.widgets import AdminBooleanSelectWidget
    3132
    3233Calling conditional_escape on the output of widget.render will simulate what
    3334happens in the template. This is easier than setting up a template and context
     
    6768>>> print conditional_escape(w.render('test', [m1.pk, m2.pk], attrs={}))
    6869<input type="text" name="test" value="1,2" class="vManyToManyRawIdAdminField" /><a href="../../../admin_widgets/member/" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/admin/selector-search.gif" width="16" height="16" alt="Lookup"></a>
    6970
     71The list should have a plainlist class, otherwise both radioselects would be rendered with square bullets in front of them in the Admin.
     72
     73>>> w = AdminBooleanSelectWidget()
     74>>> print conditional_escape(w.render('test', False))
     75<ul class="plainlist">
     76<li><label><input type="radio" name="test" value="1" /> Yes</label></li>
     77<li><label><input checked="checked" type="radio" name="test" value="2" /> No</label></li>
     78</ul>
     79
     80>>> print conditional_escape(w.render('test', True))
     81<ul class="plainlist">
     82<li><label><input checked="checked" type="radio" name="test" value="1" /> Yes</label></li>
     83<li><label><input type="radio" name="test" value="2" /> No</label></li>
     84</ul>
    7085""" % {
    7186    'ADMIN_MEDIA_PREFIX': settings.ADMIN_MEDIA_PREFIX,
    7287    'MEDIA_URL': settings.MEDIA_URL,
    73 }}
     88}, 'HOOK_TESTS': """
     89>>> from django.db import models
     90>>> from django.contrib.admin.options import BaseModelAdmin
     91
     92Make sure that the formfield_for_dbfield in the BaseModelAdmin hooks the right admin widgets to admin fields.
     93
     94>>> bma = BaseModelAdmin()
     95
     96Check widget for fields that are not hooked, should return normal widget
     97
     98>>> unhooked_fields = [
     99...     models.AutoField(primary_key=True),
     100...     models.CharField(),
     101...     models.CommaSeparatedIntegerField(),
     102...     models.DecimalField(),
     103...     models.EmailField(),
     104...     models.FilePathField(),
     105...     models.FloatField(),
     106...     models.IntegerField(),
     107...     models.IPAddressField(),
     108...     models.NullBooleanField(),
     109...     models.PhoneNumberField(),
     110...     models.PositiveIntegerField(),
     111...     models.PositiveSmallIntegerField(),
     112...     models.SlugField(),
     113...     models.SmallIntegerField(),
     114...     models.TextField(),
     115...     models.TimeField(),
     116...     models.URLField(),
     117...     models.USStateField(),
     118...     models.XMLField()
     119... ]
     120
     121>>> for model_field in unhooked_fields:
     122...     field = bma.formfield_for_dbfield(model_field)
     123...     field
     124<django.newforms.fields.CharField object at ...>
     125<django.newforms.fields.CharField object at ...>
     126<django.newforms.fields.DecimalField object at ...>
     127<django.newforms.fields.EmailField object at ...>
     128<django.newforms.fields.CharField object at ...>
     129<django.newforms.fields.FloatField object at ...>
     130<django.newforms.fields.IntegerField object at ...>
     131<django.newforms.fields.IPAddressField object at ...>
     132<django.newforms.fields.NullBooleanField object at ...>
     133<django.contrib.localflavor.us.forms.USPhoneNumberField object at ...>
     134<django.newforms.fields.IntegerField object at ...>
     135<django.newforms.fields.IntegerField object at ...>
     136<django.newforms.fields.CharField object at ...>
     137<django.newforms.fields.IntegerField object at ...>
     138<django.newforms.fields.CharField object at ...>
     139<django.newforms.fields.TimeField object at ...>
     140<django.newforms.fields.URLField object at ...>
     141<django.newforms.fields.CharField object at ...>
     142<django.newforms.fields.CharField object at ...>
     143
     144Check widget for fields that are hooked, should return special admin widgets.
     145
     146>>> field = bma.formfield_for_dbfield(models.DateTimeField())
     147>>> field.widget
     148<django.contrib.admin.widgets.AdminSplitDateTime object at ...>
     149
     150>>> field = bma.formfield_for_dbfield(models.DateField())
     151>>> field.widget
     152<django.contrib.admin.widgets.AdminDateWidget object at ...>
     153
     154>>> field = bma.formfield_for_dbfield(models.TimeField())
     155>>> field.widget
     156<django.contrib.admin.widgets.AdminTimeWidget object at ...>
     157
     158>>> field = bma.formfield_for_dbfield(models.BooleanField())
     159>>> field.widget
     160<django.contrib.admin.widgets.AdminBooleanSelectWidget object at ...>
     161
     162>>> field = bma.formfield_for_dbfield(models.ImageField())
     163>>> field.widget
     164<django.contrib.admin.widgets.AdminFileWidget object at ...>
     165
     166>>> field = bma.formfield_for_dbfield(models.FileField())
     167>>> field.widget
     168<django.contrib.admin.widgets.AdminFileWidget object at ...>
     169
     170Test ForeignKey and ManyToManyField widgets here, use the model defined
     171above to retrieve the ForeignKey field, as to be able to traverse the relation.
     172
     173Make sure that ForeignKey field returns a raw id widget when the field is flagged as such.
     174
     175>>> bma.raw_id_fields = ('band', )
     176>>> field = bma.formfield_for_dbfield(Album._meta.get_field('band'))
     177>>> field.widget
     178<django.contrib.admin.widgets.ForeignKeyRawIdWidget object at ...>
     179
     180Check to see if normal widget is returned when no raw id is selected.
     181
     182>>> bma.raw_id_fields = ()
     183>>> bma.admin_site = 'admin site'
     184>>> field = bma.formfield_for_dbfield(Album._meta.get_field('band'))
     185>>> field.widget
     186<django.newforms.widgets.Select object at ...>
     187
     188Do the same for ManyToManyField.
     189
     190>>> bma.raw_id_fields = ('members',)
     191>>> field = bma.formfield_for_dbfield(Band._meta.get_field('members'))
     192>>> field.widget
     193<django.contrib.admin.widgets.ManyToManyRawIdWidget object at ...>
     194
     195Check for no raw id in.
     196
     197>>> bma.raw_id_fields = ()
     198>>> field = bma.formfield_for_dbfield(Band._meta.get_field('members'))
     199>>> field.widget
     200<django.newforms.widgets.SelectMultiple object at ...>
     201
     202>>> bma.filter_horizontal = ('members', )
     203>>> field = bma.formfield_for_dbfield(Band._meta.get_field('members'))
     204>>> field.widget
     205<django.contrib.admin.widgets.FilteredSelectMultiple object at ...>
     206"""}
     207 No newline at end of file
  • AUTHORS

     
    283283    Philippe Raoult <philippe.raoult@n2nsoft.com>
    284284    Massimiliano Ravelli <massimiliano.ravelli@gmail.com>
    285285    Brian Ray <http://brianray.chipy.org/>
    286     remco@diji.biz
     286    Remco Wendt <remco@diji.biz>
    287287    David Reynolds <david@reynoldsfamily.org.uk>
    288288    rhettg@gmail.com
    289289    ricardojbarrios@gmail.com
Back to Top