Repository: django-cms/django-cms

Issue:
show_editable_model breaks datetime formatting
When rendering a date or datetime attribute with show_editable_model, the formatting (in settings.DATE_FORMAT ) is not applied. This is irrespective of whether you're in edit mode or not.

E.g, {% show_editable_model entry "date" %} will always render as '2014-1-12' instead of the default 'Jan 2, 2014', or any other formatting specified in settings.py.

From what I can tell, this is because every attribute is run through mark_safe() in in the CMSEditableObject get_context method. If you comment out line 710:

```
context['content'] = mark_safe(context['content'])
```

datetime objects format correctly, though this presumably breaks something else.

This also raises the question if genuinely none-safe content (e.g., user comments that might contain malicious JS) is incorrectly marked as safe when rendered with show_editable_model?



Discussion:
`mark_safe` is needed to properly render HTML-enabled fields. We can explicitly document this to alert developers to use `show_editable_model` wisely.
As for the date formatting you can use filters to trigger proper formatting: http://django-cms.readthedocs.org/en/develop/extending_cms/frontend_models.html#filters


Resolving patch:
diff --git a/cms/templatetags/cms_tags.py b/cms/templatetags/cms_tags.py
--- a/cms/templatetags/cms_tags.py
+++ b/cms/templatetags/cms_tags.py
@@ -602,7 +602,7 @@ class CMSEditableObject(InclusionTag):
         Argument('attribute'),
         Argument('edit_fields', default=None, required=False),
         Argument('language', default=None, required=False),
-        Argument('filters', default=None, resolve=False, required=False),
+        Argument('filters', default=None, required=False),
         Argument('view_url', default=None, required=False),
         Argument('view_method', default=None, required=False),
     )
@@ -704,17 +704,15 @@ def get_context(self, context, instance, attribute, edit_fields, language,
                     url_base = reverse(view_url, args=(instance.pk, language))
                     querystring['edit_fields'] = ",".join(context['edit_fields'])
             context['edit_url'] = "%s?%s" % (url_base, urlencode(querystring))
-	# content is for non-edit template content.html
-	# rendered_content is for edit template plugin.html
-	# in this templatetag both hold the same content
+        # content is for non-edit template content.html
+        # rendered_content is for edit template plugin.html
+        # in this templatetag both hold the same content
         context['content'] = mark_safe(context['content'])
         context['rendered_content'] = context['content']
         return context
 register.tag(CMSEditableObject)
 
 
-
-
 class StaticPlaceholderNode(Tag):
     name = 'static_placeholder'
     options = Options(


Test patch:
diff --git a/cms/test_utils/project/placeholderapp/models.py b/cms/test_utils/project/placeholderapp/models.py
--- a/cms/test_utils/project/placeholderapp/models.py
+++ b/cms/test_utils/project/placeholderapp/models.py
@@ -18,6 +18,7 @@ class Example1(models.Model):
     char_2 = models.CharField(u'char_2', max_length=255)
     char_3 = models.CharField(u'char_3', max_length=255)
     char_4 = models.CharField(u'char_4', max_length=255)
+    date_field = models.DateField(null=True)
     placeholder = PlaceholderField('placeholder')
 
     def callable_item(self, request):
diff --git a/cms/tests/toolbar.py b/cms/tests/toolbar.py
--- a/cms/tests/toolbar.py
+++ b/cms/tests/toolbar.py
@@ -1,6 +1,7 @@
 from __future__ import with_statement
 import re
 from django.template.defaultfilters import truncatewords
+import datetime
 from cms.views import details
 from cms.utils.compat.dj import force_unicode
 import re
@@ -310,13 +311,41 @@ def test_filters(self):
 {% load cms_tags %}
 
 {% block content %}
-<h1>{% show_editable_model instance "char_1" "" "" truncatewords:2  %}</h1>
+<h1>{% show_editable_model instance "char_1" "" "" 'truncatewords:2' %}</h1>
 {% endblock content %}
 '''
         request = self.get_page_request(page, user, edit=True)
         response = detail_view(request, ex1.pk, template_string=template_text)
         self.assertContains(response, '<h1><div class="cms_plugin cms_plugin-%s-%s-%s">%s</div></h1>' % ('placeholderapp', 'char_1', ex1.pk, truncatewords(ex1.char_1, 2)))
 
+    def test_filters_date(self):
+        user = self.get_staff()
+        page = create_page('Test', 'col_two.html', 'en', published=True)
+        ex1 = Example1(char_1="char_1, <p>hello</p>, <p>hello</p>, <p>hello</p>, <p>hello</p>", char_2="char_2", char_3="char_3",
+                       char_4="char_4", date_field=datetime.date(2012, 1, 1))
+        ex1.save()
+        template_text = '''{% extends "base.html" %}
+{% load cms_tags %}
+
+{% block content %}
+<h1>{% show_editable_model instance "date_field" %}</h1>
+{% endblock content %}
+'''
+        request = self.get_page_request(page, user, edit=True)
+
+        response = detail_view(request, ex1.pk, template_string=template_text)
+        self.assertContains(response, '<h1><div class="cms_plugin cms_plugin-%s-%s-%s">%s</div></h1>' % ('placeholderapp', 'date_field', ex1.pk, ex1.date_field.strftime("%Y-%m-%d")))
+
+        template_text = '''{% extends "base.html" %}
+{% load cms_tags %}
+
+{% block content %}
+<h1>{% show_editable_model instance "date_field" "" "" 'date:"Y m d"' %}</h1>
+{% endblock content %}
+'''
+        response = detail_view(request, ex1.pk, template_string=template_text)
+        self.assertContains(response, '<h1><div class="cms_plugin cms_plugin-%s-%s-%s">%s</div></h1>' % ('placeholderapp', 'date_field', ex1.pk, ex1.date_field.strftime("%Y %m %d")))
+
     def test_filters_notoolbar(self):
         user = self.get_staff()
         page = create_page('Test', 'col_two.html', 'en', published=True)
@@ -327,7 +356,7 @@ def test_filters_notoolbar(self):
 {% load cms_tags %}
 
 {% block content %}
-<h1>{% show_editable_model instance "char_1" "" "" truncatewords:2  %}</h1>
+<h1>{% show_editable_model instance "char_1" "" "" 'truncatewords:2'  %}</h1>
 {% endblock content %}
 '''
         request = self.get_page_request(page, user, edit=False)