[1.11.x] Fixed #27850 -- Made RelatedFieldWidgetWrapper call render() of the wrapped widget.

Backport of fb7e0e01af from master
This commit is contained in:
Collin Anderson 2017-02-20 08:48:03 -05:00 committed by Tim Graham
parent 447c6802f0
commit 808d33c1bf
4 changed files with 27 additions and 17 deletions

View File

@ -1,24 +1,24 @@
{% load i18n static %} {% load i18n static %}
<div class="related-widget-wrapper"> <div class="related-widget-wrapper">
{% include widget.template_name %} {{ rendered_widget }}
{% block links %} {% block links %}
{% spaceless %} {% spaceless %}
{% if can_change_related %} {% 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 }}" data-href-template="{{ change_related_template_url }}?{{ url_params }}"
title="{% blocktrans %}Change selected {{ model }}{% endblocktrans %}"> title="{% blocktrans %}Change selected {{ model }}{% endblocktrans %}">
<img src="{% static 'admin/img/icon-changelink.svg' %}" alt="{% trans 'Change' %}"/> <img src="{% static 'admin/img/icon-changelink.svg' %}" alt="{% trans 'Change' %}"/>
</a> </a>
{% endif %} {% endif %}
{% if can_add_related %} {% 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 }}" href="{{ add_related_url }}?{{ url_params }}"
title="{% blocktrans %}Add another {{ model }}{% endblocktrans %}"> title="{% blocktrans %}Add another {{ model }}{% endblocktrans %}">
<img src="{% static 'admin/img/icon-addlink.svg' %}" alt="{% trans 'Add' %}"/> <img src="{% static 'admin/img/icon-addlink.svg' %}" alt="{% trans 'Add' %}"/>
</a> </a>
{% endif %} {% endif %}
{% if can_delete_related %} {% 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 }}" data-href-template="{{ delete_related_template_url }}?{{ url_params }}"
title="{% blocktrans %}Delete selected {{ model }}{% endblocktrans %}"> title="{% blocktrans %}Delete selected {{ model }}{% endblocktrans %}">
<img src="{% static 'admin/img/icon-deletelink.svg' %}" alt="{% trans 'Delete' %}"/> <img src="{% static 'admin/img/icon-deletelink.svg' %}" alt="{% trans 'Delete' %}"/>

View File

@ -269,18 +269,20 @@ class RelatedFieldWidgetWrapper(forms.Widget):
current_app=self.admin_site.name, args=args) current_app=self.admin_site.name, args=args)
def get_context(self, name, value, attrs=None): 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 from django.contrib.admin.views.main import IS_POPUP_VAR, TO_FIELD_VAR
rel_opts = self.rel.model._meta rel_opts = self.rel.model._meta
info = (rel_opts.app_label, rel_opts.model_name) info = (rel_opts.app_label, rel_opts.model_name)
self.widget.choices = self.choices
url_params = '&'.join("%s=%s" % param for param in [ url_params = '&'.join("%s=%s" % param for param in [
(TO_FIELD_VAR, self.rel.get_related_field().name), (TO_FIELD_VAR, self.rel.get_related_field().name),
(IS_POPUP_VAR, 1), (IS_POPUP_VAR, 1),
]) ])
context['url_params'] = url_params context = {
context['model'] = rel_opts.verbose_name 'rendered_widget': self.widget.render(name, value, attrs),
'name': name,
'url_params': url_params,
'model': rel_opts.verbose_name,
}
if self.can_change_related: if self.can_change_related:
change_related_template_url = self.get_related_url(info, 'change', '__fk__') change_related_template_url = self.get_related_url(info, 'change', '__fk__')
context.update( context.update(

View File

@ -7,7 +7,6 @@ from __future__ import unicode_literals
import copy import copy
import datetime import datetime
import re import re
from contextlib import contextmanager
from itertools import chain from itertools import chain
from django.conf import settings from django.conf import settings
@ -647,13 +646,6 @@ class ChoiceWidget(Widget):
pass pass
return getter(name) return getter(name)
@contextmanager
def override_choices(self, choices):
old = self.choices
self.choices = choices
yield
self.choices = old
def format_value(self, value): def format_value(self, value):
"""Return selected values as a set.""" """Return selected values as a set."""
if not isinstance(value, (tuple, list)): if not isinstance(value, (tuple, list)):

View File

@ -599,6 +599,7 @@ class ManyToManyRawIdWidgetTest(TestCase):
) )
@override_settings(ROOT_URLCONF='admin_widgets.urls')
class RelatedFieldWidgetWrapperTests(SimpleTestCase): class RelatedFieldWidgetWrapperTests(SimpleTestCase):
def test_no_can_add_related(self): def test_no_can_add_related(self):
rel = Individual._meta.get_field('parent').remote_field rel = Individual._meta.get_field('parent').remote_field
@ -633,6 +634,21 @@ class RelatedFieldWidgetWrapperTests(SimpleTestCase):
self.assertTrue(wrapper.can_change_related) self.assertTrue(wrapper.can_change_related)
self.assertFalse(wrapper.can_delete_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') @override_settings(ROOT_URLCONF='admin_widgets.urls')
class AdminWidgetSeleniumTestCase(AdminSeleniumTestCase): class AdminWidgetSeleniumTestCase(AdminSeleniumTestCase):