diff --git a/django/contrib/admin/templates/admin/widgets/related_widget_wrapper.html b/django/contrib/admin/templates/admin/widgets/related_widget_wrapper.html index b6a4436953..b84ab14cca 100644 --- a/django/contrib/admin/templates/admin/widgets/related_widget_wrapper.html +++ b/django/contrib/admin/templates/admin/widgets/related_widget_wrapper.html @@ -1,24 +1,24 @@ {% load i18n static %} <div class="related-widget-wrapper"> - {% include widget.template_name %} + {{ rendered_widget }} {% block links %} {% spaceless %} {% if can_change_related %} - <a class="related-widget-wrapper-link change-related" id="change_id_{{ widget.name }}" + <a class="related-widget-wrapper-link change-related" id="change_id_{{ name }}" data-href-template="{{ change_related_template_url }}?{{ url_params }}" title="{% blocktrans %}Change selected {{ model }}{% endblocktrans %}"> <img src="{% static 'admin/img/icon-changelink.svg' %}" alt="{% trans 'Change' %}"/> </a> {% endif %} {% if can_add_related %} - <a class="related-widget-wrapper-link add-related" id="add_id_{{ widget.name }}" + <a class="related-widget-wrapper-link add-related" id="add_id_{{ name }}" href="{{ add_related_url }}?{{ url_params }}" title="{% blocktrans %}Add another {{ model }}{% endblocktrans %}"> <img src="{% static 'admin/img/icon-addlink.svg' %}" alt="{% trans 'Add' %}"/> </a> {% endif %} {% if can_delete_related %} - <a class="related-widget-wrapper-link delete-related" id="delete_id_{{ widget.name }}" + <a class="related-widget-wrapper-link delete-related" id="delete_id_{{ name }}" data-href-template="{{ delete_related_template_url }}?{{ url_params }}" title="{% blocktrans %}Delete selected {{ model }}{% endblocktrans %}"> <img src="{% static 'admin/img/icon-deletelink.svg' %}" alt="{% trans 'Delete' %}"/> diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py index 5960f82d91..39a906ed85 100644 --- a/django/contrib/admin/widgets.py +++ b/django/contrib/admin/widgets.py @@ -269,18 +269,20 @@ class RelatedFieldWidgetWrapper(forms.Widget): current_app=self.admin_site.name, args=args) def get_context(self, name, value, attrs=None): - with self.widget.override_choices(self.choices): - context = self.widget.get_context(name, value, attrs) - from django.contrib.admin.views.main import IS_POPUP_VAR, TO_FIELD_VAR rel_opts = self.rel.model._meta info = (rel_opts.app_label, rel_opts.model_name) + self.widget.choices = self.choices url_params = '&'.join("%s=%s" % param for param in [ (TO_FIELD_VAR, self.rel.get_related_field().name), (IS_POPUP_VAR, 1), ]) - context['url_params'] = url_params - context['model'] = rel_opts.verbose_name + context = { + 'rendered_widget': self.widget.render(name, value, attrs), + 'name': name, + 'url_params': url_params, + 'model': rel_opts.verbose_name, + } if self.can_change_related: change_related_template_url = self.get_related_url(info, 'change', '__fk__') context.update( diff --git a/django/forms/widgets.py b/django/forms/widgets.py index aca599ff9a..82efdef633 100644 --- a/django/forms/widgets.py +++ b/django/forms/widgets.py @@ -7,7 +7,6 @@ from __future__ import unicode_literals import copy import datetime import re -from contextlib import contextmanager from itertools import chain from django.conf import settings @@ -647,13 +646,6 @@ class ChoiceWidget(Widget): pass return getter(name) - @contextmanager - def override_choices(self, choices): - old = self.choices - self.choices = choices - yield - self.choices = old - def format_value(self, value): """Return selected values as a set.""" if not isinstance(value, (tuple, list)): diff --git a/tests/admin_widgets/tests.py b/tests/admin_widgets/tests.py index b74df4e251..8c05fa4331 100644 --- a/tests/admin_widgets/tests.py +++ b/tests/admin_widgets/tests.py @@ -599,6 +599,7 @@ class ManyToManyRawIdWidgetTest(TestCase): ) +@override_settings(ROOT_URLCONF='admin_widgets.urls') class RelatedFieldWidgetWrapperTests(SimpleTestCase): def test_no_can_add_related(self): rel = Individual._meta.get_field('parent').remote_field @@ -633,6 +634,21 @@ class RelatedFieldWidgetWrapperTests(SimpleTestCase): self.assertTrue(wrapper.can_change_related) self.assertFalse(wrapper.can_delete_related) + def test_custom_widget_render(self): + class CustomWidget(forms.Select): + def render(self, *args, **kwargs): + return 'custom render output' + rel = Album._meta.get_field('band').remote_field + widget = CustomWidget() + wrapper = widgets.RelatedFieldWidgetWrapper( + widget, rel, widget_admin_site, + can_add_related=True, + can_change_related=True, + can_delete_related=True, + ) + output = wrapper.render('name', 'value') + self.assertIn('custom render output', output) + @override_settings(ROOT_URLCONF='admin_widgets.urls') class AdminWidgetSeleniumTestCase(AdminSeleniumTestCase):