Ticket #5731: radio_admin_fields.diff
File radio_admin_fields.diff, 15.1 KB (added by , 17 years ago) |
---|
-
django/db/models/fields/__init__.py
24 24 class NOT_PROVIDED: 25 25 pass 26 26 27 HORIZONTAL, VERTICAL = 1, 228 29 27 # The values to use for "blank" in SelectFields. Will be appended to the start of most "choices" lists. 30 28 BLANK_CHOICE_DASH = [("", "---------")] 31 29 BLANK_CHOICE_NONE = [("", "None")] … … 33 31 # prepares a value for use in a LIKE query 34 32 prep_for_like_query = lambda x: smart_unicode(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_") 35 33 36 # returns the <ul> class for a given radio_admin value37 get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '')38 39 34 class FieldDoesNotExist(Exception): 40 35 pass 41 36 … … 81 76 max_length=None, unique=False, blank=False, null=False, db_index=False, 82 77 core=False, rel=None, default=NOT_PROVIDED, editable=True, serialize=True, 83 78 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, 85 80 db_tablespace=None): 86 81 self.name = name 87 82 self.verbose_name = verbose_name … … 99 94 self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month 100 95 self.unique_for_year = unique_for_year 101 96 self._choices = choices or [] 102 self.radio_admin = radio_admin103 97 self.help_text = help_text 104 98 self.db_column = db_column 105 99 self.db_tablespace = db_tablespace … … 253 247 params['max_length'] = self.max_length 254 248 255 249 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] 262 251 params['choices'] = self.get_choices_default() 263 252 else: 264 253 field_objs = self.get_manipulator_field_objs() … … 345 334 return first_choice + lst 346 335 347 336 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() 352 338 353 339 def _get_val_from_obj(self, obj): 354 340 if obj: -
django/db/models/fields/related.py
1 1 from django.db import connection, transaction 2 2 from django.db.models import signals, get_model 3 from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField , get_ul_class3 from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField 4 4 from django.db.models.related import RelatedObject 5 5 from django.utils.text import capfirst 6 6 from django.utils.translation import ugettext_lazy, string_concat, ungettext, ugettext as _ … … 496 496 497 497 def prepare_field_objs_and_params(self, manipulator, name_prefix): 498 498 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] 502 501 else: 503 if self.null: 504 field_objs = [oldforms.NullSelectField] 505 else: 506 field_objs = [oldforms.SelectField] 502 field_objs = [oldforms.SelectField] 507 503 params['choices'] = self.get_choices_default() 508 504 return field_objs, params 509 505 … … 521 517 if not obj: 522 518 # In required many-to-one fields with only one available choice, 523 519 # 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. 528 522 if not self.blank and self.choices: 529 523 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: 533 525 return {self.attname: choice_list[1][0]} 534 526 return Field.flatten_data(self, follow, obj) 535 527 … … 591 583 # ManyToManyField. This works for now. 592 584 def prepare_field_objs_and_params(self, manipulator, name_prefix): 593 585 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] 597 588 else: 598 if self.null: 599 field_objs = [oldforms.NullSelectField] 600 else: 601 field_objs = [oldforms.SelectField] 589 field_objs = [oldforms.SelectField] 602 590 params['choices'] = self.get_choices_default() 603 591 return field_objs, params 604 592 -
django/contrib/redirects/models.py
3 3 from django.utils.translation import ugettext_lazy as _ 4 4 5 5 class Redirect(models.Model): 6 site = models.ForeignKey(Site , radio_admin=models.VERTICAL)6 site = models.ForeignKey(Site) 7 7 old_path = models.CharField(_('redirect from'), max_length=200, db_index=True, 8 8 help_text=_("This should be an absolute path, excluding the domain name. Example: '/events/search/'.")) 9 9 new_path = models.CharField(_('redirect to'), max_length=200, blank=True, … … 28 28 class RedirectAdmin(admin.ModelAdmin): 29 29 list_filter = ('site',) 30 30 search_fields = ('old_path', 'new_path') 31 radio_admin_fields = { 'site': admin.VERTICAL } 31 32 32 33 admin.site.register(Redirect, RedirectAdmin) 33 34 -
django/contrib/admin/options.py
14 14 from django.utils.encoding import force_unicode 15 15 import sets 16 16 17 HORIZONTAL, VERTICAL = 1, 2 18 # returns the <ul> class for a given radio_admin value 19 get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '') 20 17 21 class IncorrectLookupParameters(Exception): 18 22 pass 19 23 … … 125 129 class BaseModelAdmin(object): 126 130 """Functionality common to both ModelAdmin and InlineAdmin.""" 127 131 raw_id_fields = () 132 radio_admin_fields = {} 128 133 fields = None 129 134 fieldsets = None 130 135 filter_vertical = () … … 174 179 if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): 175 180 if isinstance(db_field, models.ForeignKey) and db_field.name in self.raw_id_fields: 176 181 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 177 185 else: 178 186 if isinstance(db_field, models.ManyToManyField) and db_field.name in self.raw_id_fields: 179 187 kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel) … … 186 194 formfield.widget.render = widgets.RelatedFieldWidgetWrapper(formfield.widget.render, db_field.rel, self.admin_site) 187 195 return formfield 188 196 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 189 203 # For any other type of field, just call its formfield() method. 190 204 return db_field.formfield(**kwargs) 191 205 -
django/contrib/admin/__init__.py
1 from django.contrib.admin.options import ModelAdmin 1 from django.contrib.admin.options import ModelAdmin, HORIZONTAL, VERTICAL 2 2 from django.contrib.admin.options import StackedInline, TabularInline 3 3 from django.contrib.admin.sites import AdminSite, site -
tests/regressiontests/modeladmin/models.py
4 4 class Band(models.Model): 5 5 name = models.CharField(max_length=100) 6 6 bio = models.TextField() 7 def __unicode__(self): 8 return self.name 7 9 10 class 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) 8 15 16 9 17 __test__ = {'API_TESTS': """ 10 18 11 >>> from django.contrib.admin.options import ModelAdmin 19 >>> from django.contrib.admin.options import ModelAdmin, HORIZONTAL, VERTICAL 12 20 >>> from django.contrib.admin.sites import AdminSite 13 21 14 22 None of the following tests really depend on the content of the request, so … … 17 25 >>> request = None 18 26 19 27 >>> band = Band(name='The Doors', bio='') 28 >>> band.save() 20 29 21 30 Under the covers, the admin system will initialize ModelAdmin with a Model 22 31 class and an AdminSite instance, so let's just go ahead and do that manually … … 84 93 >>> ma.form_change(request, band).base_fields.keys() 85 94 ['name'] 86 95 96 # radio_admin_fields behavior ################################################ 87 97 98 First, without any radio_admin_fields specified, the widgets for ForeignKey 99 and fields with choices specified ought to be a basic Select widget. 100 For Select fields, all of the choices lists have a first entry of dashes. 88 101 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')] 89 120 121 Now specify all the fields as radio_admin_fields. Widgets should now be 122 RadioSelect, and the choices list should have a first entry of 'None' iff 123 blank=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 158 band.delete() 159 90 160 """ 91 161 } -
docs/model-api.txt
663 663 ``primary_key=True`` implies ``blank=False``, ``null=False`` and 664 664 ``unique=True``. Only one primary key is allowed on an object. 665 665 666 ``radio_admin``667 ~~~~~~~~~~~~~~~668 669 By default, Django's admin uses a select-box interface (<select>) for670 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 676 666 ``unique`` 677 667 ~~~~~~~~~~ 678 668 -
docs/admin.txt
35 35 ``ModelAdmin`` objects 36 36 ====================== 37 37 38 39 ``radio_admin_fields`` 40 ~~~~~~~~~~~~~~~~~~~~~~ 41 42 By default, Django's admin uses a select-box interface (<select>) for 43 fields that are ``ForeignKey`` or have ``choices`` set. If a field is 44 present in ``radio_admin_fields``, Django will use a radio-button interface 45 instead. ``radio_admin_fields`` is a dictionary, keyed by field names. 46 Values should be set to either django.contrib.admin.HORIZONTAL for a 47 horizontal radio-button list, or django.contrib.admin.VERTICAL for a 48 vertical presentation. 49 50 Don't include a field in ``radio_admin_fields`` unless it's a ``ForeignKey`` 51 or has ``choices`` set. 52 53 38 54 ``AdminSite`` objects 39 55 ===================== 40 56