Django

Code

Ticket #5731: 5731-unified.diff

File 5731-unified.diff, 22.4 kB (added by programmerq, 5 months ago)

unified patch against current newforms-admin

  • a/django/contrib/admin/__init__.py

    old new  
    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 
  • a/django/contrib/admin/options.py

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

    old new  
    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 
  • a/django/db/models/fields/__init__.py

    old new  
    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 or settings.DEFAULT_INDEX_TABLESPACE 
     
    255249            params['max_length'] = self.max_length 
    256250 
    257251        if self.choices: 
    258             if self.radio_admin: 
    259                 field_objs = [oldforms.RadioSelectField] 
    260                 params['ul_class'] = get_ul_class(self.radio_admin) 
    261             else: 
    262                 field_objs = [oldforms.SelectField] 
    263  
     252            field_objs = [oldforms.SelectField] 
    264253            params['choices'] = self.get_choices_default() 
    265254        else: 
    266255            field_objs = self.get_manipulator_field_objs() 
     
    347336        return first_choice + lst 
    348337 
    349338    def get_choices_default(self): 
    350         if self.radio_admin: 
    351             return self.get_choices(include_blank=self.blank, blank_choice=BLANK_CHOICE_NONE) 
    352         else: 
    353             return self.get_choices() 
     339        return self.get_choices() 
    354340 
    355341    def _get_val_from_obj(self, obj): 
    356342        if obj: 
  • a/django/db/models/fields/related.py

    old new  
    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 
  • a/django/newforms/widgets.py

    old new  
    438438 
    439439    def render(self): 
    440440        """Outputs a <ul> for this set of radio fields.""" 
    441         return mark_safe(u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>' 
    442                 % force_unicode(w) for w in self])) 
     441        return mark_safe(u'<ul%s>\n%s\n</ul>' %  
     442                         (flatatt(self.attrs),  
     443                         u'\n'.join([u'<li>%s</li>' % force_unicode(w) for w in self]))) 
    443444 
    444445class RadioSelect(Select): 
    445446    renderer = RadioFieldRenderer 
  • a/docs/admin.txt

    old new  
    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 
  • a/docs/model-api.txt

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

    old new  
    423423zero-based index. 
    424424>>> f = FrameworkForm(auto_id='id_%s') 
    425425>>> print f['language'] 
    426 <ul
     426<ul id="id_language"
    427427<li><label><input type="radio" id="id_language_0" value="P" name="language" /> Python</label></li> 
    428428<li><label><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li> 
    429429</ul> 
     
    433433ID of the *first* radio button. 
    434434>>> print f 
    435435<tr><th><label for="id_name">Name:</label></th><td><input type="text" name="name" id="id_name" /></td></tr> 
    436 <tr><th><label for="id_language_0">Language:</label></th><td><ul
     436<tr><th><label for="id_language_0">Language:</label></th><td><ul id="id_language"
    437437<li><label><input type="radio" id="id_language_0" value="P" name="language" /> Python</label></li> 
    438438<li><label><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li> 
    439439</ul></td></tr> 
    440440>>> print f.as_ul() 
    441441<li><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" /></li> 
    442 <li><label for="id_language_0">Language:</label> <ul
     442<li><label for="id_language_0">Language:</label> <ul id="id_language"
    443443<li><label><input type="radio" id="id_language_0" value="P" name="language" /> Python</label></li> 
    444444<li><label><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li> 
    445445</ul></li> 
    446446>>> print f.as_p() 
    447447<p><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" /></p> 
    448 <p><label for="id_language_0">Language:</label> <ul
     448<p><label for="id_language_0">Language:</label> <ul id="id_language"
    449449<li><label><input type="radio" id="id_language_0" value="P" name="language" /> Python</label></li> 
    450450<li><label><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li> 
    451451</ul></p> 
  • a/tests/regressiontests/forms/regressions.py

    old new  
    4040...     somechoice = ChoiceField(choices=GENDERS, widget=RadioSelect(), label=u'\xc5\xf8\xdf') 
    4141>>> f = SomeForm() 
    4242>>> f.as_p() 
    43 u'<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label> <ul>\n<li><label><input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> En tied\xe4</label></li>\n<li><label><input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> Mies</label></li>\n<li><label><input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> Nainen</label></li>\n</ul></p>' 
     43u'<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label> <ul id="id_somechoice">\n<li><label><input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> En tied\xe4</label></li>\n<li><label><input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> Mies</label></li>\n<li><label><input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> Nainen</label></li>\n</ul></p>' 
    4444 
    4545Testing choice validation with UTF-8 bytestrings as input (these are the 
    4646Russian abbreviations "мес." and "шт.". 
     
    5656>>> activate('ru') 
    5757>>> f = SomeForm({}) 
    5858>>> f.as_p() 
    59 u'<ul class="errorlist"><li>\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435.</li></ul>\n<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label> <ul>\n<li><label><input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> En tied\xe4</label></li>\n<li><label><input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> Mies</label></li>\n<li><label><input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> Nainen</label></li>\n</ul></p>' 
     59u'<ul class="errorlist"><li>\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435.</li></ul>\n<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label> <ul id="id_somechoice">\n<li><label><input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> En tied\xe4</label></li>\n<li><label><input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> Mies</label></li>\n<li><label><input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> Nainen</label></li>\n</ul></p>' 
    6060>>> deactivate() 
    6161 
    6262Deep copying translated text shouldn't raise an error 
  • a/tests/regressiontests/forms/widgets.py

    old new  
    755755# Attributes provided at instantiation are passed to the constituent inputs 
    756756>>> w = RadioSelect(attrs={'id':'foo'}) 
    757757>>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 
    758 <ul
     758<ul id="foo"
    759759<li><label><input checked="checked" type="radio" id="foo_0" value="J" name="beatle" /> John</label></li> 
    760760<li><label><input type="radio" id="foo_1" value="P" name="beatle" /> Paul</label></li> 
    761761<li><label><input type="radio" id="foo_2" value="G" name="beatle" /> George</label></li> 
     
    765765# Attributes provided at render-time are passed to the constituent inputs 
    766766>>> w = RadioSelect() 
    767767>>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')), attrs={'id':'bar'}) 
    768 <ul
     768<ul id="bar"
    769769<li><label><input checked="checked" type="radio" id="bar_0" value="J" name="beatle" /> John</label></li> 
    770770<li><label><input type="radio" id="bar_1" value="P" name="beatle" /> Paul</label></li> 
    771771<li><label><input type="radio" id="bar_2" value="G" name="beatle" /> George</label></li> 
  • a/tests/regressiontests/modeladmin/models.py

    old new  
    44class Band(models.Model): 
    55    name = models.CharField(max_length=100) 
    66    bio = models.TextField() 
     7    def __unicode__(self): 
     8        return self.name 
     9 
     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) 
    715 
    816 
    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 
    87  
    88  
     96# radio_admin_fields behavior ################################################ 
     97 
     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. 
     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')] 
     120 
     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() 
    89159 
    90160""" 
    91161}