Repository: django-oscar/django-oscar

Issue:
Order filter form in profile throws UnicodeEncodeError
Hi,

Order filtering form throws UnicodeEncodeError if site is displayed in language other than English. After debug I found that [mark_safe](https://github.com/django-oscar/django-oscar/blob/1.2.1/src/oscar/forms/widgets.py#L207) should accept unicode instead of string:

    return mark_safe(u'<div class="form-inline">'
                         ...
                         .format(div=div, input=input))


Discussion:
I am not able to reproduce this issue - have tried in several languages. Please can you provide more detailed steps to reproduce?

Resolving patch:
diff --git a/src/oscar/forms/widgets.py b/src/oscar/forms/widgets.py
--- a/src/oscar/forms/widgets.py
+++ b/src/oscar/forms/widgets.py
@@ -142,24 +142,15 @@ def multiple_replace(dict, text):
 
 
 class DateTimeWidgetMixin(object):
-    def get_format(self):
-        format = self.format
-        if hasattr(self, 'manual_format'):
-            # For django <= 1.6.5, see
-            # https://code.djangoproject.com/ticket/21173
-            if self.is_localized and not self.manual_format:
-                format = force_text(formats.get_format(self.format_key)[0])
-        else:
-            # For django >= 1.7
-            format = format or formats.get_format(self.format_key)[0]
 
-        return format
+    def get_format(self):
+        return self.format or formats.get_format(self.format_key)[0]
 
     def gett_attrs(self, attrs, format):
         if not attrs:
             attrs = {}
 
-        attrs['data-inputmask'] = "'mask': '{mask}'".format(
+        attrs['data-inputmask'] = u"'mask': '{mask}'".format(
             mask=datetime_format_to_js_input_mask(format))
 
         return attrs
@@ -177,20 +168,20 @@ def render(self, name, value, attrs=None, renderer=None):
         input = super(TimePickerInput, self).render(
             name, value, self.gett_attrs(attrs, format))
 
-        attrs = {'data-oscarWidget': 'time',
-                 'data-timeFormat':
-                 datetime_format_to_js_time_format(format),
-                 }
-
-        div = format_html('<div class="input-group date"{}>', flatatt(attrs))
-        return mark_safe('<div class="form-inline">'
-                         ' {div}'
-                         '  {input}'
-                         '  <span class="input-group-addon">'
-                         '   <i class="icon-time glyphicon-time"></i>'
-                         '  </span>'
-                         ' </div>'
-                         '</div>'
+        attrs = {
+            'data-oscarWidget': 'time',
+            'data-timeFormat': datetime_format_to_js_time_format(format),
+        }
+
+        div = format_html(u'<div class="input-group date"{}>', flatatt(attrs))
+        return mark_safe(u'<div class="form-inline">'
+                         u' {div}'
+                         u'  {input}'
+                         u'  <span class="input-group-addon">'
+                         u'   <i class="icon-time glyphicon-time"></i>'
+                         u'  </span>'
+                         u' </div>'
+                         u'</div>'
                          .format(div=div, input=input))
 
 
@@ -206,20 +197,20 @@ def render(self, name, value, attrs=None, renderer=None):
         input = super(DatePickerInput, self).render(
             name, value, self.gett_attrs(attrs, format))
 
-        attrs = {'data-oscarWidget': 'date',
-                 'data-dateFormat':
-                 datetime_format_to_js_date_format(format),
-                 }
-
-        div = format_html('<div class="input-group date"{}>', flatatt(attrs))
-        return mark_safe('<div class="form-inline">'
-                         ' {div}'
-                         '  {input}'
-                         '  <span class="input-group-addon">'
-                         '   <i class="icon-calendar glyphicon-calendar"></i>'
-                         '  </span>'
-                         ' </div>'
-                         '</div>'
+        attrs = {
+            'data-oscarWidget': 'date',
+            'data-dateFormat': datetime_format_to_js_date_format(format),
+        }
+
+        div = format_html(u'<div class="input-group date"{}>', flatatt(attrs))
+        return mark_safe(u'<div class="form-inline">'
+                         u' {div}'
+                         u'  {input}'
+                         u'  <span class="input-group-addon">'
+                         u'   <i class="icon-calendar glyphicon-calendar"></i>'
+                         u'  </span>'
+                         u' </div>'
+                         u'</div>'
                          .format(div=div, input=input))
 
 
@@ -249,20 +240,20 @@ def render(self, name, value, attrs=None, renderer=None):
         input = super(DateTimePickerInput, self).render(
             name, value, self.gett_attrs(attrs, format))
 
-        attrs = {'data-oscarWidget': 'datetime',
-                 'data-datetimeFormat':
-                 datetime_format_to_js_datetime_format(format),
-                 }
-
-        div = format_html('<div class="input-group date"{}>', flatatt(attrs))
-        return mark_safe('<div class="form-inline">'
-                         ' {div}'
-                         '  {input}'
-                         '  <span class="input-group-addon">'
-                         '   <i class="icon-calendar glyphicon-calendar"></i>'
-                         '  </span>'
-                         ' </div>'
-                         '</div>'
+        attrs = {
+            'data-oscarWidget': 'datetime',
+            'data-datetimeFormat': datetime_format_to_js_datetime_format(format),
+        }
+
+        div = format_html(u'<div class="input-group date"{}>', flatatt(attrs))
+        return mark_safe(u'<div class="form-inline">'
+                         u' {div}'
+                         u'  {input}'
+                         u'  <span class="input-group-addon">'
+                         u'   <i class="icon-calendar glyphicon-calendar"></i>'
+                         u'  </span>'
+                         u' </div>'
+                         u'</div>'
                          .format(div=div, input=input))
 
 


Test patch:
diff --git a/tests/integration/forms/test_widget.py b/tests/integration/forms/test_widget.py
--- a/tests/integration/forms/test_widget.py
+++ b/tests/integration/forms/test_widget.py
@@ -1,3 +1,6 @@
+# -*- coding: utf-8 -*-
+import datetime
+
 from django.test import TestCase
 
 from oscar.forms import widgets
@@ -20,3 +23,24 @@ def test_datetime_to_time_format_conversion(self):
         )
         for format_, expected in format_testcases:
             self.assertEqual(widgets.datetime_format_to_js_time_format(format_), expected)
+
+    def test_timepickerinput_format_unicode(self):
+        # Check that the widget can handle unicode formats
+        i = widgets.TimePickerInput(format=u'τ-%H:%M')
+        time = datetime.time(10, 47)
+        html = i.render('time', time)
+        self.assertIn(u'value="τ-10:47"', html)
+
+    def test_datepickerinput_format_unicode(self):
+        # Check that the widget can handle unicode formats
+        i = widgets.DatePickerInput(format=u'δ-%d/%m/%Y')
+        date = datetime.date(2017, 5, 1)
+        html = i.render('date', date)
+        self.assertIn(u'value="δ-01/05/2017"', html)
+
+    def test_datetimepickerinput_format_unicode(self):
+        # Check that the widget can handle unicode formats
+        i = widgets.DateTimePickerInput(format=u'δ-%d/%m/%Y %H:%M')
+        date = datetime.datetime(2017, 5, 1, 10, 57)
+        html = i.render('datetime', date)
+        self.assertIn(u'value="δ-01/05/2017 10:57"', html)