Changeset 7626
- Timestamp:
- 06/12/08 15:13:27 (3 months ago)
- Files:
-
- django/branches/newforms-admin/django/contrib/admin/__init__.py (modified) (1 diff)
- django/branches/newforms-admin/django/contrib/admin/options.py (modified) (4 diffs)
- django/branches/newforms-admin/django/contrib/admin/widgets.py (modified) (2 diffs)
- django/branches/newforms-admin/django/contrib/redirects/models.py (modified) (2 diffs)
- django/branches/newforms-admin/django/db/models/fields/__init__.py (modified) (6 diffs)
- django/branches/newforms-admin/django/db/models/fields/related.py (modified) (3 diffs)
- django/branches/newforms-admin/docs/admin.txt (modified) (1 diff)
- django/branches/newforms-admin/docs/custom_model_fields.txt (modified) (1 diff)
- django/branches/newforms-admin/docs/model-api.txt (modified) (1 diff)
- django/branches/newforms-admin/tests/regressiontests/modeladmin/models.py (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/newforms-admin/django/contrib/admin/__init__.py
r5473 r7626 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 django/branches/newforms-admin/django/contrib/admin/options.py
r7613 r7626 18 18 import sets 19 19 20 HORIZONTAL, VERTICAL = 1, 2 21 # returns the <ul> class for a given radio_admin field 22 get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '') 23 20 24 class IncorrectLookupParameters(Exception): 21 25 pass … … 134 138 filter_vertical = () 135 139 filter_horizontal = () 140 radio_fields = {} 136 141 prepopulated_fields = {} 137 142 … … 174 179 if isinstance(db_field, models.ForeignKey) and db_field.name in self.raw_id_fields: 175 180 kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel) 181 elif isinstance(db_field, models.ForeignKey) and db_field.name in self.radio_fields: 182 kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 183 'class': get_ul_class(self.radio_fields[db_field.name]), 184 }) 185 kwargs['empty_label'] = db_field.blank and _('None') or None 176 186 else: 177 187 if isinstance(db_field, models.ManyToManyField): … … 188 198 formfield.widget.render = widgets.RelatedFieldWidgetWrapper(formfield.widget.render, db_field.rel, self.admin_site) 189 199 return formfield 200 201 if db_field.choices and db_field.name in self.radio_fields: 202 kwargs['widget'] = widgets.AdminRadioSelect( 203 choices=db_field.get_choices(include_blank=db_field.blank, 204 blank_choice=[('', _('None'))]), 205 attrs={ 206 'class': get_ul_class(self.radio_fields[db_field.name]), 207 } 208 ) 190 209 191 210 # For any other type of field, just call its formfield() method. django/branches/newforms-admin/django/contrib/admin/widgets.py
r7562 r7626 4 4 5 5 from django import newforms as forms 6 from django.newforms.widgets import RadioFieldRenderer 7 from django.newforms.util import flatatt 6 8 from django.utils.datastructures import MultiValueDict 7 9 from django.utils.text import capfirst, truncate_words … … 62 64 return mark_safe(u'<p class="datetime">%s %s<br />%s %s</p>' % \ 63 65 (_('Date:'), rendered_widgets[0], _('Time:'), rendered_widgets[1])) 66 67 class AdminRadioFieldRenderer(RadioFieldRenderer): 68 def render(self): 69 """Outputs a <ul> for this set of radio fields.""" 70 return mark_safe(u'<ul%s>\n%s\n</ul>' % ( 71 flatatt(self.attrs), 72 u'\n'.join([u'<li>%s</li>' % force_unicode(w) for w in self])) 73 ) 74 75 class AdminRadioSelect(forms.RadioSelect): 76 renderer = AdminRadioFieldRenderer 64 77 65 78 class AdminFileWidget(forms.FileInput): django/branches/newforms-admin/django/contrib/redirects/models.py
r5828 r7626 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/'.")) … … 29 29 list_filter = ('site',) 30 30 search_fields = ('old_path', 'new_path') 31 radio_fields = {'site': admin.VERTICAL} 31 32 32 33 admin.site.register(Redirect, RedirectAdmin) django/branches/newforms-admin/django/db/models/fields/__init__.py
r7500 r7626 27 27 pass 28 28 29 HORIZONTAL, VERTICAL = 1, 230 31 29 # The values to use for "blank" in SelectFields. Will be appended to the start of most "choices" lists. 32 30 BLANK_CHOICE_DASH = [("", "---------")] … … 35 33 # prepares a value for use in a LIKE query 36 34 prep_for_like_query = lambda x: smart_unicode(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_") 37 38 # returns the <ul> class for a given radio_admin value39 get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '')40 35 41 36 class FieldDoesNotExist(Exception): … … 88 83 editable=True, serialize=True, unique_for_date=None, 89 84 unique_for_month=None, unique_for_year=None, validator_list=None, 90 choices=None, radio_admin=None, help_text='', db_column=None,91 db_tablespace=None,auto_created=False):85 choices=None, help_text='', db_column=None, db_tablespace=None, 86 auto_created=False): 92 87 self.name = name 93 88 self.verbose_name = verbose_name … … 106 101 self.unique_for_year = unique_for_year 107 102 self._choices = choices or [] 108 self.radio_admin = radio_admin109 103 self.help_text = help_text 110 104 self.db_column = db_column … … 286 280 287 281 if self.choices: 288 if self.radio_admin: 289 field_objs = [oldforms.RadioSelectField] 290 params['ul_class'] = get_ul_class(self.radio_admin) 291 else: 292 field_objs = [oldforms.SelectField] 282 field_objs = [oldforms.SelectField] 293 283 294 284 params['choices'] = self.get_choices_default() … … 378 368 379 369 def get_choices_default(self): 380 if self.radio_admin: 381 return self.get_choices(include_blank=self.blank, blank_choice=BLANK_CHOICE_NONE) 382 else: 383 return self.get_choices() 370 return self.get_choices() 384 371 385 372 def _get_val_from_obj(self, obj): django/branches/newforms-admin/django/db/models/fields/related.py
r7584 r7626 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_class,FieldDoesNotExist3 from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist 4 4 from django.db.models.related import RelatedObject 5 5 from django.db.models.query_utils import QueryWrapper … … 629 629 def prepare_field_objs_and_params(self, manipulator, name_prefix): 630 630 params = {'validator_list': self.validator_list[:], 'member_name': name_prefix + self.attname} 631 if self.radio_admin: 632 field_objs = [oldforms.RadioSelectField] 633 params['ul_class'] = get_ul_class(self.radio_admin) 631 if self.null: 632 field_objs = [oldforms.NullSelectField] 634 633 else: 635 if self.null: 636 field_objs = [oldforms.NullSelectField] 637 else: 638 field_objs = [oldforms.SelectField] 634 field_objs = [oldforms.SelectField] 639 635 params['choices'] = self.get_choices_default() 640 636 return field_objs, params … … 661 657 # In required many-to-one fields with only one available choice, 662 658 # select that one available choice. Note: For SelectFields 663 # (radio_admin=False), we have to check that the length of choices 664 # is *2*, not 1, because SelectFields always have an initial 665 # "blank" value. Otherwise (radio_admin=True), we check that the 666 # length is 1. 659 # we have to check that the length of choices is *2*, not 1, 660 # because SelectFields always have an initial "blank" value. 667 661 if not self.blank and self.choices: 668 662 choice_list = self.get_choices_default() 669 if self.radio_admin and len(choice_list) == 1: 670 return {self.attname: choice_list[0][0]} 671 if not self.radio_admin and len(choice_list) == 2: 663 if len(choice_list) == 2: 672 664 return {self.attname: choice_list[1][0]} 673 665 return Field.flatten_data(self, follow, obj) django/branches/newforms-admin/docs/admin.txt
r7618 r7626 345 345 If this isn't provided, the Django admin will use the model's default ordering. 346 346 347 ``radio_fields`` 348 ---------------- 349 350 By default, Django's admin uses a select-box interface (<select>) for 351 fields that are ``ForeignKey`` or have ``choices`` set. If a field is present 352 in ``radio_fields``, Django will use a radio-button interface instead. 353 Assuming ``group`` is a ``ForeignKey`` on the ``Person`` model:: 354 355 class PersonAdmin(admin.ModelAdmin): 356 radio_fields = {"group": admin.VERTICAL} 357 358 You have the choice of using ``HORIZONTAL`` or ``VERTICAL`` from the 359 ``django.contrib.admin`` module. 360 361 Don't include a field in ``radio_fields`` unless it's a ``ForeignKey`` or has 362 ``choices`` set. 363 347 364 ``save_as`` 348 365 ----------- django/branches/newforms-admin/docs/custom_model_fields.txt
r7351 r7626 205 205 * ``validator_list`` 206 206 * ``choices`` 207 * ``radio_admin``208 207 * ``help_text`` 209 208 * ``db_column`` django/branches/newforms-admin/docs/model-api.txt
r7616 r7626 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 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 665 676 666 ``unique`` django/branches/newforms-admin/tests/regressiontests/modeladmin/models.py
r7360 r7626 1 1 # coding: utf-8 2 2 from django.db import models 3 from datetime import date 3 4 4 5 class Band(models.Model): … … 6 7 bio = models.TextField() 7 8 sign_date = models.DateField() 9 10 def __unicode__(self): 11 return self.name 12 13 class Concert(models.Model): 14 main_band = models.ForeignKey(Band, related_name='main_concerts') 15 opening_band = models.ForeignKey(Band, related_name='opening_concerts', 16 blank=True) 17 day = models.CharField(max_length=3, choices=((1, 'Fri'), (2, 'Sat'))) 18 transport = models.CharField(max_length=100, choices=( 19 (1, 'Plane'), 20 (2, 'Train'), 21 (3, 'Bus') 22 ), blank=True) 8 23 9 24 10 25 __test__ = {'API_TESTS': """ 11 26 12 >>> from django.contrib.admin.options import ModelAdmin 27 >>> from django.contrib.admin.options import ModelAdmin, HORIZONTAL, VERTICAL 13 28 >>> from django.contrib.admin.sites import AdminSite 14 29 … … 18 33 >>> request = None 19 34 20 >>> band = Band(name='The Doors', bio='') 35 # the sign_date is not 100 percent accurate ;) 36 >>> band = Band(name='The Doors', bio='', sign_date=date(1965, 1, 1)) 37 >>> band.save() 21 38 22 39 Under the covers, the admin system will initialize ModelAdmin with a Model … … 106 123 <class 'django.contrib.admin.widgets.AdminDateWidget'> 107 124 125 # radio_fields behavior ################################################ 126 127 First, without any radio_fields specified, the widgets for ForeignKey 128 and fields with choices specified ought to be a basic Select widget. 129 For Select fields, all of the choices lists have a first entry of dashes. 130 131 >>> cma = ModelAdmin(Concert, site) 132 >>> cmafa = cma.get_form(request) 133 134 >>> type(cmafa.base_fields['main_band'].widget) 135 <class 'django.newforms.widgets.Select'> 136 >>> list(cmafa.base_fields['main_band'].widget.choices) 137 [(u'', u'---------'), (1, u'The Doors')] 138 139 >>> type(cmafa.base_fields['opening_band'].widget) 140 <class 'django.newforms.widgets.Select'> 141 >>> list(cmafa.base_fields['opening_band'].widget.choices) 142 [(u'', u'---------'), (1, u'The Doors')] 143 144 >>> type(cmafa.base_fields['day'].widget) 145 <class 'django.newforms.widgets.Select'> 146 >>> list(cmafa.base_fields['day'].widget.choices) 147 [('', '---------'), (1, 'Fri'), (2, 'Sat')] 148 149 >>> type(cmafa.base_fields['transport'].widget) 150 <class 'django.newforms.widgets.Select'> 151 >>> list(cmafa.base_fields['transport'].widget.choices) 152 [('', '---------'), (1, 'Plane'), (2, 'Train'), (3, 'Bus')] 153 154 Now specify all the fields as radio_fields. Widgets should now be 155 RadioSelect, and the choices list should have a first entry of 'None' iff 156 blank=True for the model field. Finally, the widget should have the 157 'radiolist' attr, and 'inline' as well if the field is specified HORIZONTAL. 158 159 >>> class ConcertAdmin(ModelAdmin): 160 ... radio_fields = { 161 ... 'main_band': HORIZONTAL, 162 ... 'opening_band': VERTICAL, 163 ... 'day': VERTICAL, 164 ... 'transport': HORIZONTAL, 165 ... } 166 167 >>> cma = ConcertAdmin(Concert, site) 168 >>> cmafa = cma.get_form(request) 169 170 >>> type(cmafa.base_fields['main_band'].widget) 171 <class 'django.contrib.admin.widgets.AdminRadioSelect'> 172 >>> cmafa.base_fields['main_band'].widget.attrs 173 {'class': 'radiolist inline'} 174 >>> list(cmafa.base_fields['main_band'].widget.choices) 175 [(1, u'The Doors')] 176 177 >>> type(cmafa.base_fields['opening_band'].widget) 178 <class 'django.contrib.admin.widgets.AdminRadioSelect'> 179 >>> cmafa.base_fields['opening_band'].widget.attrs 180 {'class': 'radiolist'} 181 >>> list(cmafa.base_fields['opening_band'].widget.choices) 182 [(u'', u'None'), (1, u'The Doors')] 183 184 >>> type(cmafa.base_fields['day'].widget) 185 <class 'django.contrib.admin.widgets.AdminRadioSelect'> 186 >>> cmafa.base_fields['day'].widget.attrs 187 {'class': 'radiolist'} 188 >>> list(cmafa.base_fields['day'].widget.choices) 189 [(1, 'Fri'), (2, 'Sat')] 190 191 >>> type(cmafa.base_fields['transport'].widget) 192 <class 'django.contrib.admin.widgets.AdminRadioSelect'> 193 >>> cmafa.base_fields['transport'].widget.attrs 194 {'class': 'radiolist inline'} 195 >>> list(cmafa.base_fields['transport'].widget.choices) 196 [('', u'None'), (1, 'Plane'), (2, 'Train'), (3, 'Bus')] 197 198 >>> band.delete() 199 108 200 """ 109 201 }
