Reputation: 18122
Let say we have a message like this :
messages.add_message(request, messages.SUCCESS,
_('Document <a href="%(url)s">%(doc_type_name)s %(name)s (%(fname)s)</a> created.') % {
'doc_type_name': conditional_escape(document.doc_type.name),
'name': conditional_escape(document.title),
'fname': conditional_escape(document.name),
'url': document.get_absolute_url()
})
Here it will work only if we display the message with {{ message|safe }}
but we don't want that since if there is some code in %(name)
it will be executed too.
If I use:
messages.add_message(request, messages.SUCCESS,
mark_safe(_('Document <a href="%(url)s">%(doc_type_name)s %(name)s (%(fname)s)</a> created.') % {
'doc_type_name': conditional_escape(document.doc_type.name),
'name': conditional_escape(document.title),
'fname': conditional_escape(document.name),
'url': document.get_absolute_url()
}))
The mark_safe
doesn't work.
I read a solution over there : https://stackoverflow.com/a/12600388/186202
But it is the reverse that I need here:
_('Document %s created.') % mark_safe('')
And as soon as it goes through the ugettext function
it is not safe anymore.
How should I do?
Upvotes: 2
Views: 3350
Reputation: 1145
Previous response are correct: you should avoid mixing python and html as much as possible.
To solve your issue:
from django.utils import six # Python 3 compatibility
from django.utils.functional import lazy
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
mark_safe_lazy = lazy(mark_safe, six.text_type)
then:
lazy_string = mark_safe_lazy(_("<p>My <strong>string!</strong></p>"))
Found in django documentation: https://docs.djangoproject.com/en/1.9/topics/i18n/translation/#s-other-uses-of-lazy-in-delayed-translations
Upvotes: 2
Reputation: 15738
You are trying to mix view and logic by placing HTML inside Python code. Well, sometimes you just have to do this but it is not the case.
mark_safe() returns SafeString object which is treated by Django templates specially. If SafeString evaluated by ugettext or % you will get string again, it is an expected behaviour. You can not mark safe only formatting string, either complete output with doc name/title etc or everything is not safe. Ie, it will not work this way.
You can put HTML into template and use render_to_string(), and probably it is the best option.
Are document title, name and doc_type.name set by user? If not, you can skip mark_safe and document using HTML in document properties as feature.
Upvotes: 4