Ticket #5731: radio_admin_fields.diff

File radio_admin_fields.diff, 15.1 KB (added by Karen Tracey <kmtracey@…>, 17 years ago)
  • django/db/models/fields/__init__.py

     
    2424class NOT_PROVIDED:
    2525    pass
    2626
    27 HORIZONTAL, VERTICAL = 1, 2
    28 
    2927# The values to use for "blank" in SelectFields. Will be appended to the start of most "choices" lists.
    3028BLANK_CHOICE_DASH = [("", "---------")]
    3129BLANK_CHOICE_NONE = [("", "None")]
     
    3331# prepares a value for use in a LIKE query
    3432prep_for_like_query = lambda x: smart_unicode(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_")
    3533
    36 # returns the <ul> class for a given radio_admin value
    37 get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '')
    38 
    3934class FieldDoesNotExist(Exception):
    4035    pass
    4136
     
    8176        max_length=None, unique=False, blank=False, null=False, db_index=False,
    8277        core=False, rel=None, default=NOT_PROVIDED, editable=True, serialize=True,
    8378        unique_for_date=None, unique_for_month=None, unique_for_year=None,
    84         validator_list=None, choices=None, radio_admin=None, help_text='', db_column=None,
     79        validator_list=None, choices=None, help_text='', db_column=None,
    8580        db_tablespace=None):
    8681        self.name = name
    8782        self.verbose_name = verbose_name
     
    9994        self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month
    10095        self.unique_for_year = unique_for_year
    10196        self._choices = choices or []
    102         self.radio_admin = radio_admin
    10397        self.help_text = help_text
    10498        self.db_column = db_column
    10599        self.db_tablespace = db_tablespace
     
    253247            params['max_length'] = self.max_length
    254248
    255249        if self.choices:
    256             if self.radio_admin:
    257                 field_objs = [oldforms.RadioSelectField]
    258                 params['ul_class'] = get_ul_class(self.radio_admin)
    259             else:
    260                 field_objs = [oldforms.SelectField]
    261 
     250            field_objs = [oldforms.SelectField]
    262251            params['choices'] = self.get_choices_default()
    263252        else:
    264253            field_objs = self.get_manipulator_field_objs()
     
    345334        return first_choice + lst
    346335
    347336    def get_choices_default(self):
    348         if self.radio_admin:
    349             return self.get_choices(include_blank=self.blank, blank_choice=BLANK_CHOICE_NONE)
    350         else:
    351             return self.get_choices()
     337        return self.get_choices()
    352338
    353339    def _get_val_from_obj(self, obj):
    354340        if obj:
  • django/db/models/fields/related.py

     
    11from django.db import connection, transaction
    22from django.db.models import signals, get_model
    3 from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, get_ul_class
     3from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField
    44from django.db.models.related import RelatedObject
    55from django.utils.text import capfirst
    66from django.utils.translation import ugettext_lazy, string_concat, ungettext, ugettext as _
     
    496496
    497497    def prepare_field_objs_and_params(self, manipulator, name_prefix):
    498498        params = {'validator_list': self.validator_list[:], 'member_name': name_prefix + self.attname}
    499         if self.radio_admin:
    500             field_objs = [oldforms.RadioSelectField]
    501             params['ul_class'] = get_ul_class(self.radio_admin)
     499        if self.null:
     500            field_objs = [oldforms.NullSelectField]
    502501        else:
    503             if self.null:
    504                 field_objs = [oldforms.NullSelectField]
    505             else:
    506                 field_objs = [oldforms.SelectField]
     502            field_objs = [oldforms.SelectField]
    507503        params['choices'] = self.get_choices_default()
    508504        return field_objs, params
    509505
     
    521517        if not obj:
    522518            # In required many-to-one fields with only one available choice,
    523519            # select that one available choice. Note: For SelectFields
    524             # (radio_admin=False), we have to check that the length of choices
    525             # is *2*, not 1, because SelectFields always have an initial
    526             # "blank" value. Otherwise (radio_admin=True), we check that the
    527             # length is 1.
     520            # we have to check that the length of choices is *2*, not 1,
     521            # because SelectFields always have an initial "blank" value.
    528522            if not self.blank and self.choices:
    529523                choice_list = self.get_choices_default()
    530                 if self.radio_admin and len(choice_list) == 1:
    531                     return {self.attname: choice_list[0][0]}
    532                 if not self.radio_admin and len(choice_list) == 2:
     524                if len(choice_list) == 2:
    533525                    return {self.attname: choice_list[1][0]}
    534526        return Field.flatten_data(self, follow, obj)
    535527
     
    591583    # ManyToManyField. This works for now.
    592584    def prepare_field_objs_and_params(self, manipulator, name_prefix):
    593585        params = {'validator_list': self.validator_list[:], 'member_name': name_prefix + self.attname}
    594         if self.radio_admin:
    595             field_objs = [oldforms.RadioSelectField]
    596             params['ul_class'] = get_ul_class(self.radio_admin)
     586        if self.null:
     587            field_objs = [oldforms.NullSelectField]
    597588        else:
    598             if self.null:
    599                 field_objs = [oldforms.NullSelectField]
    600             else:
    601                 field_objs = [oldforms.SelectField]
     589            field_objs = [oldforms.SelectField]
    602590        params['choices'] = self.get_choices_default()
    603591        return field_objs, params
    604592
  • django/contrib/redirects/models.py

     
    33from django.utils.translation import ugettext_lazy as _
    44
    55class Redirect(models.Model):
    6     site = models.ForeignKey(Site, radio_admin=models.VERTICAL)
     6    site = models.ForeignKey(Site)
    77    old_path = models.CharField(_('redirect from'), max_length=200, db_index=True,
    88        help_text=_("This should be an absolute path, excluding the domain name. Example: '/events/search/'."))
    99    new_path = models.CharField(_('redirect to'), max_length=200, blank=True,
     
    2828class RedirectAdmin(admin.ModelAdmin):
    2929    list_filter = ('site',)
    3030    search_fields = ('old_path', 'new_path')
     31    radio_admin_fields = { 'site': admin.VERTICAL }
    3132
    3233admin.site.register(Redirect, RedirectAdmin)
    3334
  • django/contrib/admin/options.py

     
    1414from django.utils.encoding import force_unicode
    1515import sets
    1616
     17HORIZONTAL, VERTICAL = 1, 2
     18# returns the <ul> class for a given radio_admin value
     19get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '')
     20
    1721class IncorrectLookupParameters(Exception):
    1822    pass
    1923
     
    125129class BaseModelAdmin(object):
    126130    """Functionality common to both ModelAdmin and InlineAdmin."""
    127131    raw_id_fields = ()
     132    radio_admin_fields = {}
    128133    fields = None
    129134    fieldsets = None
    130135    filter_vertical = ()
     
    174179        if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)):
    175180            if isinstance(db_field, models.ForeignKey) and db_field.name in self.raw_id_fields:
    176181                kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel)
     182            elif isinstance(db_field, models.ForeignKey) and db_field.name in self.radio_admin_fields:
     183                kwargs['widget'] = forms.RadioSelect(attrs={'class':get_ul_class(self.radio_admin_fields[db_field.name])})
     184                kwargs['empty_label'] = db_field.blank and _('None') or None
    177185            else:
    178186                if isinstance(db_field, models.ManyToManyField) and db_field.name in self.raw_id_fields:
    179187                    kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel)
     
    186194                formfield.widget.render = widgets.RelatedFieldWidgetWrapper(formfield.widget.render, db_field.rel, self.admin_site)
    187195            return formfield
    188196
     197        if db_field.choices and db_field.name in self.radio_admin_fields:
     198            kwargs['widget'] = forms.RadioSelect(choices=db_field.get_choices(include_blank=db_field.blank,
     199                                                                              blank_choice=[("", _('None'))]),
     200                                                 attrs={'class':get_ul_class(self.radio_admin_fields[db_field.name])})
     201            return db_field.formfield(**kwargs)
     202
    189203        # For any other type of field, just call its formfield() method.
    190204        return db_field.formfield(**kwargs)
    191205
  • django/contrib/admin/__init__.py

     
    1 from django.contrib.admin.options import ModelAdmin
     1from django.contrib.admin.options import ModelAdmin, HORIZONTAL, VERTICAL
    22from django.contrib.admin.options import StackedInline, TabularInline
    33from django.contrib.admin.sites import AdminSite, site
  • tests/regressiontests/modeladmin/models.py

     
    44class Band(models.Model):
    55    name = models.CharField(max_length=100)
    66    bio = models.TextField()
     7    def __unicode__(self):
     8        return self.name
    79
     10class Gig(models.Model):
     11    main_band = models.ForeignKey(Band, related_name='main_gigs')
     12    opening_band = models.ForeignKey(Band, related_name='opening_gigs', blank=True)
     13    day = models.CharField(max_length=3, choices=((1, 'Fri'), (2, 'Sat')))
     14    transport = models.CharField(max_length=100, choices=((1, 'Plane'), (2, 'Train'), (3, 'Bus')), blank=True)
    815
     16
    917__test__ = {'API_TESTS': """
    1018
    11 >>> from django.contrib.admin.options import ModelAdmin
     19>>> from django.contrib.admin.options import ModelAdmin, HORIZONTAL, VERTICAL
    1220>>> from django.contrib.admin.sites import AdminSite
    1321
    1422None of the following tests really depend on the content of the request, so
     
    1725>>> request = None
    1826
    1927>>> band = Band(name='The Doors', bio='')
     28>>> band.save()
    2029
    2130Under the covers, the admin system will initialize ModelAdmin with a Model
    2231class and an AdminSite instance, so let's just go ahead and do that manually
     
    8493>>> ma.form_change(request, band).base_fields.keys()
    8594['name']
    8695
     96# radio_admin_fields behavior ################################################
    8797
     98First, without any radio_admin_fields specified, the widgets for ForeignKey
     99and fields with choices specified ought to be a basic Select widget.
     100For Select fields, all of the choices lists have a first entry of dashes.
    88101
     102>>> gma = ModelAdmin(Gig, site)
     103>>> gmafa = gma.form_add(request)
     104>>> gmafa.base_fields['main_band'].widget
     105<django.newforms.widgets.Select object at...
     106>>> list(gmafa.base_fields['main_band'].widget.choices)
     107[(u'', u'---------'), (1, u'The Doors')]
     108>>> gmafa.base_fields['opening_band'].widget
     109<django.newforms.widgets.Select object at...
     110>>> list(gmafa.base_fields['opening_band'].widget.choices)
     111[(u'', u'---------'), (1, u'The Doors')]
     112>>> gmafa.base_fields['day'].widget
     113<django.newforms.widgets.Select object at...
     114>>> list(gmafa.base_fields['day'].widget.choices)
     115[('', '---------'), (1, 'Fri'), (2, 'Sat')]
     116>>> gmafa.base_fields['transport'].widget
     117<django.newforms.widgets.Select object at...
     118>>> list(gmafa.base_fields['transport'].widget.choices)
     119[('', '---------'), (1, 'Plane'), (2, 'Train'), (3, 'Bus')]
    89120
     121Now specify all the fields as radio_admin_fields.  Widgets should now be
     122RadioSelect, and the choices list should have a first entry of 'None' iff
     123blank=True for the model field.  Finally, the widget should have the
     124'radiolist' attr, and 'inline' as well if the field is specified HORIZONTAL.
     125
     126>>> class GigAdmin(ModelAdmin):
     127...     radio_admin_fields = {'main_band':HORIZONTAL, 'opening_band':VERTICAL, 'day':VERTICAL, 'transport':HORIZONTAL }
     128
     129>>> gma = GigAdmin(Gig, site)
     130>>> gmafa = gma.form_add(request)
     131>>> gmafa.base_fields['main_band'].widget
     132<django.newforms.widgets.RadioSelect object at...
     133>>> gmafa.base_fields['main_band'].widget.attrs
     134{'class': 'radiolist inline'}
     135>>> list(gmafa.base_fields['main_band'].widget.choices)
     136[(1, u'The Doors')]
     137>>> gmafa.base_fields['opening_band'].widget
     138<django.newforms.widgets.RadioSelect object at...
     139>>> gmafa.base_fields['opening_band'].widget.attrs
     140{'class': 'radiolist'}
     141>>> list(gmafa.base_fields['opening_band'].widget.choices)
     142[(u'', u'None'), (1, u'The Doors')]
     143>>> gmafa.base_fields['day'].widget
     144<django.newforms.widgets.RadioSelect object at...
     145>>> gmafa.base_fields['day'].widget.attrs
     146{'class': 'radiolist'}
     147>>> list(gmafa.base_fields['day'].widget.choices)
     148[(1, 'Fri'), (2, 'Sat')]
     149>>> gmafa.base_fields['transport'].widget
     150<django.newforms.widgets.RadioSelect object at...
     151>>> gmafa.base_fields['transport'].widget.attrs
     152{'class': 'radiolist inline'}
     153>>> list(gmafa.base_fields['transport'].widget.choices)
     154[('', u'None'), (1, 'Plane'), (2, 'Train'), (3, 'Bus')]
     155
     156
     157
     158band.delete()
     159
    90160"""
    91161}
  • docs/model-api.txt

     
    663663``primary_key=True`` implies ``blank=False``, ``null=False`` and
    664664``unique=True``. Only one primary key is allowed on an object.
    665665
    666 ``radio_admin``
    667 ~~~~~~~~~~~~~~~
    668 
    669 By default, Django's admin uses a select-box interface (<select>) for
    670 fields that are ``ForeignKey`` or have ``choices`` set. If ``radio_admin``
    671 is set to ``True``, Django will use a radio-button interface instead.
    672 
    673 Don't use this for a field unless it's a ``ForeignKey`` or has ``choices``
    674 set.
    675 
    676666``unique``
    677667~~~~~~~~~~
    678668
  • docs/admin.txt

     
    3535``ModelAdmin`` objects
    3636======================
    3737
     38
     39``radio_admin_fields``
     40~~~~~~~~~~~~~~~~~~~~~~
     41
     42By default, Django's admin uses a select-box interface (<select>) for
     43fields that are ``ForeignKey`` or have ``choices`` set. If a field is
     44present in ``radio_admin_fields``, Django will use a radio-button interface
     45instead. ``radio_admin_fields`` is a dictionary, keyed by field names.
     46Values should be set to either django.contrib.admin.HORIZONTAL for a
     47horizontal radio-button list, or django.contrib.admin.VERTICAL for a
     48vertical presentation.
     49
     50Don't include a field in ``radio_admin_fields`` unless it's a ``ForeignKey``
     51or has ``choices`` set.
     52
     53
    3854``AdminSite`` objects
    3955=====================
    4056
Back to Top