From d8c5544e91803b026a245932c4608123880b2966 Mon Sep 17 00:00:00 2001 From: seroy Date: Mon, 17 Jul 2017 22:53:47 +0300 Subject: [PATCH 1/4] Use template-based widget rendering in AdminLocalizedFieldWidget --- .../localized_fields/admin/widget.html | 12 ++-- localized_fields/widgets.py | 57 ++++--------------- 2 files changed, 18 insertions(+), 51 deletions(-) diff --git a/localized_fields/templates/localized_fields/admin/widget.html b/localized_fields/templates/localized_fields/admin/widget.html index 2d9152e..2c14e03 100644 --- a/localized_fields/templates/localized_fields/admin/widget.html +++ b/localized_fields/templates/localized_fields/admin/widget.html @@ -1,14 +1,16 @@ +{% with widget_id=widget.attrs.id %}
-{% for key, widget in widgets %} -
- {{ widget }} +{% for widget in widget.subwidgets %} +
+ {% include widget.template_name %}
{% endfor %}
+{% endwith %} diff --git a/localized_fields/widgets.py b/localized_fields/widgets.py index 451a724..ab1fdcc 100644 --- a/localized_fields/widgets.py +++ b/localized_fields/widgets.py @@ -3,7 +3,6 @@ from typing import List from django.conf import settings from django import forms from django.contrib.admin import widgets -from django.template.loader import render_to_string from .value import LocalizedValue @@ -49,6 +48,16 @@ class LocalizedFieldWidget(forms.MultiWidget): return result + @staticmethod + def build_widget_attrs(widget, value, attrs): + attrs = dict(attrs) # Copy attrs to avoid modifying the argument. + + if (not widget.use_required_attribute(value) or not widget.is_required) \ + and 'required' in attrs: + del attrs['required'] + + return attrs + class LocalizedCharFieldWidget(LocalizedFieldWidget): """Widget that has an input box for every language.""" @@ -61,52 +70,8 @@ class LocalizedFileWidget(LocalizedFieldWidget): class AdminLocalizedFieldWidget(LocalizedFieldWidget): + template_name = 'localized_fields/admin/widget.html' widget = widgets.AdminTextareaWidget - template = 'localized_fields/admin/widget.html' - - def render(self, name, value, attrs=None): - if self.is_localized: - for widget in self.widgets: - widget.is_localized = self.is_localized - - # value is a list of values, each corresponding to a widget - # in self.widgets. - if not isinstance(value, list): - value = self.decompress(value) - - output = [] - final_attrs = self.build_attrs(attrs) - id_ = final_attrs.get('id') - - for i, widget in enumerate(self.widgets): - try: - widget_value = value[i] - except IndexError: - widget_value = None - if id_: - final_attrs = dict(final_attrs, id='%s_%s' % (id_, i)) - - widget_attrs = self.build_widget_attrs(widget, widget_value, final_attrs) - output.append(widget.render(name + '_%s' % i, widget_value, widget_attrs)) - - context = { - 'id': final_attrs.get('id'), - 'name': name, - 'widgets': zip([code for code, lang in settings.LANGUAGES], output), - 'available_languages': settings.LANGUAGES - } - - return render_to_string(self.template, context) - - @staticmethod - def build_widget_attrs(widget, value, attrs): - attrs = dict(attrs) # Copy attrs to avoid modifying the argument. - - if (not widget.use_required_attribute(value) or not widget.is_required) \ - and 'required' in attrs: - del attrs['required'] - - return attrs class AdminLocalizedCharFieldWidget(AdminLocalizedFieldWidget): From 69cf0df166583a0038f96446903635cdef6645fd Mon Sep 17 00:00:00 2001 From: seroy Date: Tue, 18 Jul 2017 00:29:44 +0300 Subject: [PATCH 2/4] Use template-based widget rendering in AdminLocalizedFieldWidget --- localized_fields/widgets.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/localized_fields/widgets.py b/localized_fields/widgets.py index ab1fdcc..9163fcf 100644 --- a/localized_fields/widgets.py +++ b/localized_fields/widgets.py @@ -48,6 +48,38 @@ class LocalizedFieldWidget(forms.MultiWidget): return result + def get_context(self, name, value, attrs): + context = super(forms.MultiWidget, self).get_context(name, value, attrs) + if self.is_localized: + for widget in self.widgets: + widget.is_localized = self.is_localized + # value is a list of values, each corresponding to a widget + # in self.widgets. + if not isinstance(value, list): + value = self.decompress(value) + + final_attrs = context['widget']['attrs'] + input_type = final_attrs.pop('type', None) + id_ = final_attrs.get('id') + subwidgets = [] + for i, widget in enumerate(self.widgets): + if input_type is not None: + widget.input_type = input_type + widget_name = '%s_%s' % (name, i) + try: + widget_value = value[i] + except IndexError: + widget_value = None + if id_: + widget_attrs = final_attrs.copy() + widget_attrs['id'] = '%s_%s' % (id_, i) + else: + widget_attrs = final_attrs + widget_attrs = self.build_widget_attrs(widget, widget_value, widget_attrs) + subwidgets.append(widget.get_context(widget_name, widget_value, widget_attrs)['widget']) + context['widget']['subwidgets'] = subwidgets + return context + @staticmethod def build_widget_attrs(widget, value, attrs): attrs = dict(attrs) # Copy attrs to avoid modifying the argument. From 6522e38f18c9a85872990dd26c375f65abd0d06d Mon Sep 17 00:00:00 2001 From: seroy Date: Tue, 18 Jul 2017 01:03:50 +0300 Subject: [PATCH 3/4] Added tests for LocalizedFieldWidget.get_context method --- tests/test_file_widget.py | 24 ++++++++++++++++++++++++ tests/test_widget.py | 13 +++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tests/test_file_widget.py diff --git a/tests/test_file_widget.py b/tests/test_file_widget.py new file mode 100644 index 0000000..87404ea --- /dev/null +++ b/tests/test_file_widget.py @@ -0,0 +1,24 @@ +from django.test import TestCase + +from localized_fields.value import LocalizedFileValue +from localized_fields.widgets import LocalizedFileWidget + + +class LocalizedFileWidgetTestCase(TestCase): + """Tests the workings of the :see:LocalizedFiledWidget class.""" + + @staticmethod + def test_get_context(): + """Tests whether the :see:get_context correctly + handles 'required' attribute, separately for each subwidget.""" + + widget = LocalizedFileWidget() + widget.widgets[0].is_required = True + widget.widgets[1].is_required = True + widget.widgets[2].is_required = False + context = widget.get_context(name='test', + value=LocalizedFileValue(dict(en='test')), + attrs=dict(required=True)) + assert 'required' not in context['widget']['subwidgets'][0]['attrs'] + assert context['widget']['subwidgets'][1]['attrs']['required'] + assert 'required' not in context['widget']['subwidgets'][2]['attrs'] diff --git a/tests/test_widget.py b/tests/test_widget.py index a1ed753..c0f07de 100644 --- a/tests/test_widget.py +++ b/tests/test_widget.py @@ -42,3 +42,16 @@ class LocalizedFieldWidgetTestCase(TestCase): for _, value in zip(settings.LANGUAGES, decompressed_values): assert not value + + @staticmethod + def test_get_context(): + """Tests whether the :see:get_context correctly + handles 'required' attribute, separately for each subwidget.""" + + widget = LocalizedFieldWidget() + widget.widgets[0].is_required = True + widget.widgets[1].is_required = False + context = widget.get_context(name='test', value=LocalizedValue(), + attrs=dict(required=True)) + assert context['widget']['subwidgets'][0]['attrs']['required'] + assert 'required' not in context['widget']['subwidgets'][1]['attrs'] From 940587d7480119ed7aa5cc9ee138a1184737cbb7 Mon Sep 17 00:00:00 2001 From: seroy Date: Tue, 18 Jul 2017 01:06:49 +0300 Subject: [PATCH 4/4] Updated django requirement --- requirements/test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/test.txt b/requirements/test.txt index 1eb0eaa..7b475f0 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -1,7 +1,7 @@ -r base.txt coverage==4.2 -Django==1.10.2 +Django==1.11 django-autoslug==1.9.3 django-bleach==0.3.0 django-coverage-plugin==1.3.1