Django

Code

Changeset 7626

Show
Ignore:
Timestamp:
06/12/08 15:13:27 (3 months ago)
Author:
brosner
Message:

newforms-admin: Fixed #5731 -- Implemented ModelAdmin?.radio_fields to match trunk's radio_admin. Removed legacy code and added tests. Thanks Karen Tracey for the initial work.

Files:

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 
     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 
  • django/branches/newforms-admin/django/contrib/admin/options.py

    r7613 r7626  
    1818import sets 
    1919 
     20HORIZONTAL, VERTICAL = 1, 2 
     21# returns the <ul> class for a given radio_admin field 
     22get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '') 
     23 
    2024class IncorrectLookupParameters(Exception): 
    2125    pass 
     
    134138    filter_vertical = () 
    135139    filter_horizontal = () 
     140    radio_fields = {} 
    136141    prepopulated_fields = {} 
    137142 
     
    174179            if isinstance(db_field, models.ForeignKey) and db_field.name in self.raw_id_fields: 
    175180                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 
    176186            else: 
    177187                if isinstance(db_field, models.ManyToManyField): 
     
    188198                formfield.widget.render = widgets.RelatedFieldWidgetWrapper(formfield.widget.render, db_field.rel, self.admin_site) 
    189199            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            ) 
    190209 
    191210        # For any other type of field, just call its formfield() method. 
  • django/branches/newforms-admin/django/contrib/admin/widgets.py

    r7562 r7626  
    44 
    55from django import newforms as forms 
     6from django.newforms.widgets import RadioFieldRenderer 
     7from django.newforms.util import flatatt 
    68from django.utils.datastructures import MultiValueDict 
    79from django.utils.text import capfirst, truncate_words 
     
    6264        return mark_safe(u'<p class="datetime">%s %s<br />%s %s</p>' % \ 
    6365            (_('Date:'), rendered_widgets[0], _('Time:'), rendered_widgets[1])) 
     66 
     67class 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 
     75class AdminRadioSelect(forms.RadioSelect): 
     76    renderer = AdminRadioFieldRenderer 
    6477 
    6578class AdminFileWidget(forms.FileInput): 
  • django/branches/newforms-admin/django/contrib/redirects/models.py

    r5828 r7626  
    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/'.")) 
     
    2929    list_filter = ('site',) 
    3030    search_fields = ('old_path', 'new_path') 
     31    radio_fields = {'site': admin.VERTICAL} 
    3132 
    3233admin.site.register(Redirect, RedirectAdmin) 
  • django/branches/newforms-admin/django/db/models/fields/__init__.py

    r7500 r7626  
    2727    pass 
    2828 
    29 HORIZONTAL, VERTICAL = 1, 2 
    30  
    3129# The values to use for "blank" in SelectFields. Will be appended to the start of most "choices" lists. 
    3230BLANK_CHOICE_DASH = [("", "---------")] 
     
    3533# prepares a value for use in a LIKE query 
    3634prep_for_like_query = lambda x: smart_unicode(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_") 
    37  
    38 # returns the <ul> class for a given radio_admin value 
    39 get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '') 
    4035 
    4136class FieldDoesNotExist(Exception): 
     
    8883            editable=True, serialize=True, unique_for_date=None, 
    8984            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): 
    9287        self.name = name 
    9388        self.verbose_name = verbose_name 
     
    106101        self.unique_for_year = unique_for_year 
    107102        self._choices = choices or [] 
    108         self.radio_admin = radio_admin 
    109103        self.help_text = help_text 
    110104        self.db_column = db_column 
     
    286280 
    287281        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] 
    293283 
    294284            params['choices'] = self.get_choices_default() 
     
    378368 
    379369    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() 
    384371 
    385372    def _get_val_from_obj(self, obj): 
  • django/branches/newforms-admin/django/db/models/fields/related.py

    r7584 r7626  
    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, FieldDoesNotExist 
     3from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist 
    44from django.db.models.related import RelatedObject 
    55from django.db.models.query_utils import QueryWrapper 
     
    629629    def prepare_field_objs_and_params(self, manipulator, name_prefix): 
    630630        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] 
    634633        else: 
    635             if self.null: 
    636                 field_objs = [oldforms.NullSelectField] 
    637             else: 
    638                 field_objs = [oldforms.SelectField] 
     634            field_objs = [oldforms.SelectField] 
    639635        params['choices'] = self.get_choices_default() 
    640636        return field_objs, params 
     
    661657            # In required many-to-one fields with only one available choice, 
    662658            # 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. 
    667661            if not self.blank and self.choices: 
    668662                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: 
    672664                    return {self.attname: choice_list[1][0]} 
    673665        return Field.flatten_data(self, follow, obj) 
  • django/branches/newforms-admin/docs/admin.txt

    r7618 r7626  
    345345If this isn't provided, the Django admin will use the model's default ordering. 
    346346 
     347``radio_fields`` 
     348---------------- 
     349 
     350By default, Django's admin uses a select-box interface (<select>) for 
     351fields that are ``ForeignKey`` or have ``choices`` set. If a field is present 
     352in ``radio_fields``, Django will use a radio-button interface instead. 
     353Assuming ``group`` is a ``ForeignKey`` on the ``Person`` model:: 
     354 
     355    class PersonAdmin(admin.ModelAdmin): 
     356        radio_fields = {"group": admin.VERTICAL} 
     357 
     358You have the choice of using ``HORIZONTAL`` or ``VERTICAL`` from the 
     359``django.contrib.admin`` module. 
     360 
     361Don't include a field in ``radio_fields`` unless it's a ``ForeignKey`` or has 
     362``choices`` set. 
     363 
    347364``save_as`` 
    348365----------- 
  • django/branches/newforms-admin/docs/custom_model_fields.txt

    r7351 r7626  
    205205    * ``validator_list`` 
    206206    * ``choices`` 
    207     * ``radio_admin`` 
    208207    * ``help_text`` 
    209208    * ``db_column`` 
  • django/branches/newforms-admin/docs/model-api.txt

    r7616 r7626  
    663663``primary_key=True`` implies ``blank=False``, ``null=False`` and 
    664664``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>) 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. 
    675665 
    676666``unique`` 
  • django/branches/newforms-admin/tests/regressiontests/modeladmin/models.py

    r7360 r7626  
    11# coding: utf-8 
    22from django.db import models 
     3from datetime import date 
    34 
    45class Band(models.Model): 
     
    67    bio = models.TextField() 
    78    sign_date = models.DateField() 
     9     
     10    def __unicode__(self): 
     11        return self.name 
     12 
     13class 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) 
    823 
    924 
    1025__test__ = {'API_TESTS': """ 
    1126 
    12 >>> from django.contrib.admin.options import ModelAdmin 
     27>>> from django.contrib.admin.options import ModelAdmin, HORIZONTAL, VERTICAL 
    1328>>> from django.contrib.admin.sites import AdminSite 
    1429 
     
    1833>>> request = None 
    1934 
    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() 
    2138 
    2239Under the covers, the admin system will initialize ModelAdmin with a Model 
     
    106123<class 'django.contrib.admin.widgets.AdminDateWidget'> 
    107124 
     125# radio_fields behavior ################################################ 
     126 
     127First, without any radio_fields specified, the widgets for ForeignKey 
     128and fields with choices specified ought to be a basic Select widget. 
     129For 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 
     154Now specify all the fields as radio_fields.  Widgets should now be 
     155RadioSelect, and the choices list should have a first entry of 'None' iff 
     156blank=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 
    108200""" 
    109201}