1

I want to add a link to terms and conditions in help_text property of django model_field, basically I would like to write code like:

 class UserRegisterData(models.Model):

    accepted_terms = models.BooleanField(
           ...
           help_text = u""Terms and conditions are avilable on <a href="{reg}">this iste</a> stronie""".format(reg = reverse("terms"))
     )

whis obviously fails, because urlconfs are unprepared while models are being instantiated.

I even tried to wrap help_test in SimpleLazyObject but it still didn't work.

I'd rather didn't touch the template code. Is there any way to achieve this without hardcoding url in either string or settings?

jb.
  • 23,300
  • 18
  • 98
  • 136

2 Answers2

6

I think this is what django.core.urlresolvers.reverse_lazy is meant for.
For information: it was added to django in 1.4, so if you're using an earlier version, you'll need to upgrade.


As mentionned in the comments, you'll still need to go around the string formatting which breaks the "laziness" of the URL reverse:

from django.utils.translation import string_concat

# ...

help_text = string_concat( # Happens to be lazy!
                u'Terms and conditions are available on <a href="', 
                reverse_lazy("terms"),
                u'">this site</a>"',
)
Thomas Orozco
  • 53,284
  • 11
  • 113
  • 116
  • Well it doesn't work, because: lazy_reverse result is nevertheless evaluated when passed as parameter to `format`, and even if it didn't it still would be evaluated because during model creation django calls `force_unicode` on `help_text`. – jb. Jan 02 '13 at 19:27
  • @jb. The `force_unicode` shouldn't be an issue as it probably is called late enough: for instance, you can put lazily evaluated translations in help text. Formatting is indeed problematic, but I think it can be solved using `django.utils.translation.string_concat`, which basically is a lazy string concatenation (and will give you an `unicode` string). – Thomas Orozco Jan 02 '13 at 19:32
  • It really was an issue, at some point I did something like: help_text = SimpleLazyObject(lambda : u"""...""".format(reg = reverse("terms"))) which which was evaluated by 'force_unicode' during model creation process, which is to early. – jb. Jan 02 '13 at 20:03
  • @jb. Did you try what I suggested? [I am pretty sure lazy objects can be used in `help_text`](https://docs.djangoproject.com/en/1.0/topics/i18n/#lazy-translation). If it still doesn't work, could you point me to the line where `force_unicode` is being called? – Thomas Orozco Jan 02 '13 at 20:15
  • Ok. In the end I used something like: – jb. Jan 02 '13 at 20:23
  • In the end I needed lazy on two levels: def _lazy_format(format_string, *args, **kwargs): return format_string.format(*args, **kwargs) lazy_format = lazy(_lazy_format, unicode) help_text = lazy_format("format", reg = reverse_lazy("terms")) If you paste it in your answer I'll accept it. – jb. Jan 02 '13 at 20:26
  • @jb. I re-suggested the alternative using library code, although I like your lazy_format too! – Thomas Orozco Jan 02 '13 at 20:33
3

As of Django 2.1 django.utils.translation.string_concat() has been removed and marked as deprecated in earlier versions.

In order to evaluate lazy objects in a str.format() like syntax you now have to use format_lazy() instead.

Example:

my_field = forms.BooleanField(
        # ...
        help_text=format_lazy(
            '''
            Please click <a href='{}'>here</a>.
            ''',
            reverse_lazy('my-viewname')
        )
)

Note that you may have to explicitly mark the help_text content as safe for HTML output purposes. A possible solution to do so could be within the template and the help of the safe filter:

{{ my_field|safe }}
Yannic Hamann
  • 4,655
  • 32
  • 50