Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using django's `reverse_lazy` and concatenizing it

Tags:

python

django

I want to insert a resolved URL into a string, used as the help_text of a form field:

class ContactForm(forms.Form):

    [...]

    email_sender = forms.EmailField(
        label="Votre email",
        widget=forms.EmailInput(attrs={'disabled': 'disabled'}),
        help_text="[...], <a href='{}'>[...]</a>.".format(reverse_lazy('account_email'))
    )

But inserting the reversed URL into the string is not possible, because the format function (or any concatenation way I tried) is not "lazy", and wants to produce the output immediately.

I get the following error:

django.core.exceptions.ImproperlyConfigured: The included urlconf 'myproject.urls' does not appear to have any patterns in it. If you see valid patterns in the file then the issue is probably caused by a circular import.

For example, using the following code works perfectly, but is not what I want :)

    email_sender = forms.EmailField(
        help_text=reverse_lazy('account_email')
    )

So how do I concatenate a string of "lazy" values?

like image 376
Mickaël Avatar asked Dec 19 '22 02:12

Mickaël


1 Answers

Note: This was written in the times of Django 2. While the essence is still valid as of Django 4, the helper function described in this post is now provided out-of-the-box as format_lazy.


You cannot concatenate lazy strings in Django. The implementation is very basic, it's not even actual lazy strings, it's lazy function calls, they may return other types. When you do reverse_lazy, you do just get a lazy function call with no special other behavior

So, just play by the rules. If you need a string to be lazily computed, create a lazy function yourself:

from django.utils.functional import lazy

def email_sender_help_text():
    return "[...], <a href='{}'>[...]</a>.".format(reverse('account_email'))

email_sender_help_text_lazy = lazy(email_sender_help_text, str)

You can now use it:

email_sender = forms.EmailField(
    help_text=email_sender_help_text_lazy()
)

Or, for a more general version:

from django.utils.functional import lazy

def format(string, *args, **kwargs):
    return string.format(*args, **kwargs)
lazy_format = lazy(format, str)

 

help_text=lazy_format("<a href='{}'>", reverse_lazy('account_email'))

You may also want to check out django.utils.functional.allow_lazy.


Later edit:
Since Django 3, Django provides exactly that helper function, as format_lazy. So use that instead of recreating it.

like image 156
spectras Avatar answered Dec 24 '22 00:12

spectras