Fixed #27850 -- Made RelatedFieldWidgetWrapper call render() of the wrapped widget.

This commit is contained in:
Collin Anderson 2017-02-20 08:48:03 -05:00 committed by Tim Graham
parent c743af82cf
commit fb7e0e01af
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

@ -266,18 +266,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

@ -5,7 +5,6 @@ HTML Widget classes
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
@ -630,13 +629,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

@ -596,6 +596,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
@ -630,6 +631,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):