diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index b0eb113359..35c3cde0fc 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -154,7 +154,8 @@ class BaseModelAdmin(object): """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: - kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, using=db) + kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, + self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), @@ -174,7 +175,8 @@ class BaseModelAdmin(object): db = kwargs.get('using') if db_field.name in self.raw_id_fields: - kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, using=db) + kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, + self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py index 713ce63831..038351e6da 100644 --- a/django/contrib/admin/widgets.py +++ b/django/contrib/admin/widgets.py @@ -4,7 +4,7 @@ Form Widget classes specific to the Django admin site. import copy from django import forms -from django.core.urlresolvers import reverse, NoReverseMatch +from django.core.urlresolvers import reverse from django.forms.widgets import RadioFieldRenderer from django.forms.util import flatatt from django.templatetags.static import static @@ -112,29 +112,38 @@ class ForeignKeyRawIdWidget(forms.TextInput): A Widget for displaying ForeignKeys in the "raw_id" interface rather than in a \n\n' % admin_media_prefix() ) def test_stacked_render(self): - w = FilteredSelectMultiple('test', True) + w = widgets.FilteredSelectMultiple('test', True) self.assertEqual( conditional_escape(w.render('test', 'test')), '\n' % admin_media_prefix() @@ -210,14 +207,14 @@ class FilteredSelectMultipleWidgetTest(DjangoTestCase): class AdminSplitDateTimeWidgetTest(DjangoTestCase): def test_render(self): - w = AdminSplitDateTime() + w = widgets.AdminSplitDateTime() self.assertEqual( conditional_escape(w.render('test', datetime(2007, 12, 1, 9, 30))), '

Date:
Time:

', ) def test_localization(self): - w = AdminSplitDateTime() + w = widgets.AdminSplitDateTime() with self.settings(USE_L10N=True): with translation.override('de-at'): @@ -235,7 +232,7 @@ class AdminFileWidgetTest(DjangoTestCase): name='Hybrid Theory', cover_art=r'albums\hybrid_theory.jpg' ) - w = AdminFileWidget() + w = widgets.AdminFileWidget() self.assertEqual( conditional_escape(w.render('test', album.cover_art)), '

Currently: albums\hybrid_theory.jpg
Change:

' % { 'STORAGE_URL': default_storage.url('') }, @@ -255,10 +252,10 @@ class ForeignKeyRawIdWidgetTest(DjangoTestCase): ) rel = models.Album._meta.get_field('band').rel - w = ForeignKeyRawIdWidget(rel) + w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) self.assertEqual( conditional_escape(w.render('test', band.pk, attrs={})), - ' Lookup Linkin Park' % dict(admin_media_prefix(), bandpk=band.pk), + ' Lookup Linkin Park' % dict(admin_media_prefix(), bandpk=band.pk) ) def test_relations_to_non_primary_key(self): @@ -270,17 +267,42 @@ class ForeignKeyRawIdWidgetTest(DjangoTestCase): barcode=87, name='Core', parent=apple ) rel = models.Inventory._meta.get_field('parent').rel - w = ForeignKeyRawIdWidget(rel) + w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) self.assertEqual( w.render('test', core.parent_id, attrs={}), - ' Lookup Apple' % admin_media_prefix(), + ' Lookup Apple' % admin_media_prefix() ) + def test_fk_related_model_not_in_admin(self): + # FK to a model not registered with admin site. Raw ID widget shoud + # have no magnifying glass link. See #16542 + big_honeycomb = models.Honeycomb.objects.create(location='Old tree') + big_honeycomb.bee_set.create() + rel = models.Bee._meta.get_field('honeycomb').rel + + w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) + self.assertEqual( + conditional_escape(w.render('honeycomb_widget', big_honeycomb.pk, attrs={})), + ' Honeycomb object' % {'hcombpk': big_honeycomb.pk} + ) + + def test_fk_to_self_model_not_in_admin(self): + # FK to self, not registered with admin site. Raw ID widget shoud have + # no magnifying glass link. See #16542 + subject1 = models.Individual.objects.create(name='Subject #1') + models.Individual.objects.create(name='Child', parent=subject1) + rel = models.Individual._meta.get_field('parent').rel + + w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) + self.assertEqual( + conditional_escape(w.render('individual_widget', subject1.pk, attrs={})), + ' Individual object' % {'subj1pk': subject1.pk} + ) def test_proper_manager_for_label_lookup(self): # see #9258 rel = models.Inventory._meta.get_field('parent').rel - w = ForeignKeyRawIdWidget(rel) + w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) hidden = models.Inventory.objects.create( barcode=93, name='Hidden', hidden=True @@ -290,31 +312,28 @@ class ForeignKeyRawIdWidgetTest(DjangoTestCase): ) self.assertEqual( w.render('test', child_of_hidden.parent_id, attrs={}), - ' Lookup Hidden' % admin_media_prefix(), + ' Lookup Hidden' % admin_media_prefix() ) class ManyToManyRawIdWidgetTest(DjangoTestCase): def test_render(self): band = models.Band.objects.create(name='Linkin Park') - band.album_set.create( - name='Hybrid Theory', cover_art=r'albums\hybrid_theory.jpg' - ) m1 = models.Member.objects.create(name='Chester') m2 = models.Member.objects.create(name='Mike') band.members.add(m1, m2) rel = models.Band._meta.get_field('members').rel - w = ManyToManyRawIdWidget(rel) + w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site) self.assertEqual( conditional_escape(w.render('test', [m1.pk, m2.pk], attrs={})), - ' Lookup' % dict(admin_media_prefix(), m1pk=m1.pk, m2pk=m2.pk), + ' Lookup' % dict(admin_media_prefix(), m1pk=m1.pk, m2pk=m2.pk) ) self.assertEqual( conditional_escape(w.render('test', [m1.pk])), - ' Lookup' % dict(admin_media_prefix(), m1pk=m1.pk, m2pk=m2.pk), + ' Lookup' % dict(admin_media_prefix(), m1pk=m1.pk) ) self.assertEqual(w._has_changed(None, None), False) @@ -324,10 +343,31 @@ class ManyToManyRawIdWidgetTest(DjangoTestCase): self.assertEqual(w._has_changed([1, 2], [u'1']), True) self.assertEqual(w._has_changed([1, 2], [u'1', u'3']), True) + def test_m2m_related_model_not_in_admin(self): + # M2M relationship with model not registered with admin site. Raw ID + # widget shoud have no magnifying glass link. See #16542 + consultor1 = models.Advisor.objects.create(name='Rockstar Techie') + + c1 = models.Company.objects.create(name='Doodle') + c2 = models.Company.objects.create(name='Pear') + consultor1.companies.add(c1, c2) + rel = models.Advisor._meta.get_field('companies').rel + + w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site) + self.assertEqual( + conditional_escape(w.render('company_widget1', [c1.pk, c2.pk], attrs={})), + '' % {'c1pk': c1.pk, 'c2pk': c2.pk} + ) + + self.assertEqual( + conditional_escape(w.render('company_widget2', [c1.pk])), + '' % {'c1pk': c1.pk} + ) + class RelatedFieldWidgetWrapperTests(DjangoTestCase): def test_no_can_add_related(self): - rel = models.Inventory._meta.get_field('parent').rel - w = AdminRadioSelect() + rel = models.Individual._meta.get_field('parent').rel + w = widgets.AdminRadioSelect() # Used to fail with a name error. - w = RelatedFieldWidgetWrapper(w, rel, admin.site) + w = widgets.RelatedFieldWidgetWrapper(w, rel, widget_admin_site) self.assertFalse(w.can_add_related) diff --git a/tests/regressiontests/admin_widgets/widgetadmin.py b/tests/regressiontests/admin_widgets/widgetadmin.py index 6f15d9208b..ea738125fe 100644 --- a/tests/regressiontests/admin_widgets/widgetadmin.py +++ b/tests/regressiontests/admin_widgets/widgetadmin.py @@ -27,4 +27,14 @@ site = WidgetAdmin(name='widget-admin') site.register(models.User) site.register(models.Car, CarAdmin) site.register(models.CarTire, CarTireAdmin) + +site.register(models.Member) +site.register(models.Band) site.register(models.Event, EventAdmin) +site.register(models.Album) + +site.register(models.Inventory) + +site.register(models.Bee) + +site.register(models.Advisor)