Ticket #25: select_filter_for_Django_1_4.diff

File select_filter_for_Django_1_4.diff, 8.4 KB (added by jimallman <jim@…>, 3 years ago)

Attempted migration to Django 1.4 (un-tested! and possibly not useful :)

  • AUTHORS

    diff --git a/AUTHORS b/AUTHORS
    index 8224cda..443ba92 100644
    a b answer newbie questions, and generally made Django that much better: 
    9090    Mark Biggers <biggers@utsl.com>
    9191    Paul Bissex <http://e-scribe.com/>
    9292    Simon Blanchard
     93    Sean Bleier <sebleier@gmail.com>
    9394    David Blewett <david@dawninglight.net>
    9495    Matt Boersma <matt@sprout.org>
    9596    boobsd@gmail.com
    answer newbie questions, and generally made Django that much better: 
    227228    Scot Hacker <shacker@birdhouse.org>
    228229    dAniel hAhler
    229230    hambaloney
     231    Chuck Harmston <chuck@chuckharmston.com>
    230232    Brian Harring <ferringb@gmail.com>
    231233    Brant Harris
    232234    Ronny Haryanto <http://ronny.haryan.to/>
  • django/contrib/admin/options.py

    diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
    index 3a0ad74..3deb0f1 100644
    a b class BaseModelAdmin(object): 
    163163                'class': get_ul_class(self.radio_fields[db_field.name]),
    164164            })
    165165            kwargs['empty_label'] = db_field.blank and _('None') or None
     166        elif db_field.name in self.filter_vertical:
     167            kwargs['widget'] = widgets.FilteredSelectSingle(db_field.verbose_name)
    166168
    167169        return db_field.formfield(**kwargs)
    168170
    class InlineModelAdmin(BaseModelAdmin): 
    13751377        if self.prepopulated_fields:
    13761378            js.extend(['urlify.js', 'prepopulate.min.js'])
    13771379        if self.filter_vertical or self.filter_horizontal:
    1378             js.extend(['SelectBox.js', 'SelectFilter2.js'])
     1380            js.extend(['SelectBox.js', 'SelectFilter2.js', 'fkfilter.js'])
    13791381        return forms.Media(js=[static('admin/js/%s' % url) for url in js])
    13801382
    13811383    def get_formset(self, request, obj=None, **kwargs):
  • django/contrib/admin/static/admin/css/widgets.css

    diff --git a/django/contrib/admin/static/admin/css/widgets.css b/django/contrib/admin/static/admin/css/widgets.css
    index 2989f2f..451f3e9 100644
    a b  
    55    float: left;
    66}
    77
     8.selector-single{
     9        width: 282px !important;
     10}
     11
    812.selector select {
    913    width: 270px;
    1014    height: 17.2em;
  • django/contrib/admin/validation.py

    diff --git a/django/contrib/admin/validation.py b/django/contrib/admin/validation.py
    index 733f89d..500bfcb 100644
    a b def validate_base(cls, model): 
    323323        check_isseq(cls, 'filter_vertical', cls.filter_vertical)
    324324        for idx, field in enumerate(cls.filter_vertical):
    325325            f = get_field(cls, model, opts, 'filter_vertical', field)
    326             if not isinstance(f, models.ManyToManyField):
     326            if not isinstance(f, (models.ManyToManyField, models.ForeignKey)):
    327327                raise ImproperlyConfigured("'%s.filter_vertical[%d]' must be "
    328                     "a ManyToManyField." % (cls.__name__, idx))
     328                    "a ManyToManyField or ForeignKey." % (cls.__name__, idx))
    329329
    330330    # filter_horizontal
    331331    if hasattr(cls, 'filter_horizontal'):
  • django/contrib/admin/widgets.py

    diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py
    index 0d1f2a9..0bd1b0c 100644
    a b from django.utils.safestring import mark_safe 
    1515from django.utils.encoding import force_unicode
    1616
    1717
     18class FilteredSelectSingle(forms.Select):
     19    """
     20    A Select with a JavaScript filter interface.
     21    """
     22    #class Media:
     23    #    js = (settings.ADMIN_MEDIA_PREFIX + "js/fkfilter.js",)
     24    # TODO: mimic newer 'def media' below...
     25    @property
     26    def media(self):
     27        js = ["core.js", "fkfilter.js"]
     28        return forms.Media(js=[static("admin/js/%s" % path) for path in js])
     29
     30    def __init__(self, verbose_name, attrs=None, choices=()):
     31        self.verbose_name = verbose_name
     32        super(FilteredSelectSingle, self).__init__(attrs, choices)
     33
     34    def render(self, name, value, attrs={}, choices=()):
     35        attrs['class'] = 'selectfilter'
     36        output = [super(FilteredSelectSingle, self).render(
     37            name, value, attrs, choices)]
     38        output.append((
     39            '<script type="text/javascript">'
     40            'django.jQuery(document).ready(function(){'
     41            'django.jQuery("#id_%s").fk_filter("%s")'
     42            '});'
     43            '</script>'
     44        ) % (name, self.verbose_name.replace('"', '\\"'),));
     45        return mark_safe(u''.join(output))
     46
     47
    1848class FilteredSelectMultiple(forms.SelectMultiple):
    1949    """
    2050    A SelectMultiple with a JavaScript filter interface.
  • docs/ref/contrib/admin/index.txt

    diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
    index 2590243..c218036 100644
    a b subclass:: 
    303303
    304304    Same as :attr:`~ModelAdmin.filter_horizontal`, but uses a vertical display
    305305    of the filter interface with the box of unselected options appearing above
    306     the box of selected options.
     306    the box of selected options  You can also add a
     307    :class:`~django.db.models.ForeignKey` to this list and a text bo will
     308    allow you to narrow your search for a particular object through a
     309    potentially large list of options.
    307310
    308311.. attribute:: ModelAdmin.form
    309312
  • tests/regressiontests/admin_widgets/tests.py

    diff --git a/tests/regressiontests/admin_widgets/tests.py b/tests/regressiontests/admin_widgets/tests.py
    index 08a1a59..186a602 100644
    a b class AdminForeignKeyRawIdWidget(DjangoTestCase): 
    190190        self.assertEqual(lookup1, lookup2)
    191191
    192192
     193class FilteredSelectSingleWidgetTest(DjangoTestCase):
     194    def test_render(self):
     195        w = widgets.FilteredSelectSingle('test')
     196        self.assertEqual(
     197            conditional_escape(w.render('test', 'test')),
     198            '<select name="test" class="selectfilter">\n</select><script type="text/javascript">django.jQuery(document).ready(function(){django.jQuery("#id_test").fk_filter("test")});</script>'
     199        )
     200
    193201class FilteredSelectMultipleWidgetTest(DjangoTestCase):
    194202    def test_render(self):
    195203        w = widgets.FilteredSelectMultiple('test', False)
  • tests/regressiontests/modeladmin/tests.py

    diff --git a/tests/regressiontests/modeladmin/tests.py b/tests/regressiontests/modeladmin/tests.py
    index 9b60945..99092be 100644
    a b from django.contrib.admin.options import (ModelAdmin, TabularInline, 
    88    HORIZONTAL, VERTICAL)
    99from django.contrib.admin.sites import AdminSite
    1010from django.contrib.admin.validation import validate
    11 from django.contrib.admin.widgets import AdminDateWidget, AdminRadioSelect
     11from django.contrib.admin.widgets import AdminDateWidget, AdminRadioSelect, \
     12     FilteredSelectSingle
    1213from django.contrib.admin import (SimpleListFilter,
    1314     BooleanFieldListFilter)
    1415from django.core.exceptions import ImproperlyConfigured
    class ModelAdminTests(TestCase): 
    493494            list(ma.get_formsets(request))[0]().forms[0].fields.keys(),
    494495            ['extra', 'transport', 'id', 'DELETE', 'main_band'])
    495496
     497    def test_filter_vertical_foreignkey(self):
     498        class ConcertModelAdmin(ModelAdmin):
     499            filter_vertical = ('main_band',)
     500
     501        cma = ConcertModelAdmin(Concert, self.site)
     502        cmafa = cma.get_form(request)
     503
     504        self.assertEqual(type(cmafa.base_fields['main_band'].widget.widget),
     505            FilteredSelectSingle)
     506        self.assertEqual(type(cmafa.base_fields['opening_band'].widget.widget),
     507            Select)
     508
     509        self.assertEqual(
     510            list(cmafa.base_fields['main_band'].widget.choices),
     511            [(u'', u'---------'), (self.band.id, u'The Doors')])
     512
     513        self.assertEqual(
     514            type(cmafa.base_fields['opening_band'].widget.widget), Select)
     515        self.assertEqual(
     516            list(cmafa.base_fields['opening_band'].widget.choices),
     517            [(u'', u'---------'), (self.band.id, u'The Doors')])
     518
     519        self.assertEqual(type(cmafa.base_fields['day'].widget), Select)
     520        self.assertEqual(list(cmafa.base_fields['day'].widget.choices),
     521            [('', '---------'), (1, 'Fri'), (2, 'Sat')])
     522
     523        self.assertEqual(type(cmafa.base_fields['transport'].widget),
     524            Select)
     525        self.assertEqual(
     526            list(cmafa.base_fields['transport'].widget.choices),
     527            [('', '---------'), (1, 'Plane'), (2, 'Train'), (3, 'Bus')])
     528
    496529
    497530class ValidationTests(unittest.TestCase):
    498531    def test_validation_only_runs_in_debug(self):
Back to Top