gettext_lazy not working in Django template

I am using this field in my model:

class PeriodChoices(models.TextChoices):
    ONE = "a", _("1 month")
    TWO = "b", _("2 months")
    THREE = "c", _("3 months")
    FOUR = "d", _("4 months")
    FIVE = "e", _("5 months")
    SIX = "f", _("6 months")
    SEVEN = "g", _("7 months")
    EIGHT = "h", _("8 months")
    NINE = "i", _("9 months")
    TEN = "j", _("10 months")
    ELEVEN = "k", _("11 months")
    TWELVE = "l", _("12 months")
    TWELVE_PLUS = "m", _("12+ months")
    __empty__ = _('(Unknown)')

period = models.CharField(max_length=20, choices=PeriodChoices.choices, blank=True,)

I am using “a” - “m” for my primary values since I want these choices to be sorted correctly (i.e. “11 months” should be sorted after “2 months”).

This works great in the admin and when rendered through a Django model form. The problem is when the model’s period is called in the template, where I get the letter in stead of the translation:

The template part used for this is:

{{ model_obj|getattribute:field }}

Where field=“period” and getattribute is a custom template tag that returns:

    return getattr(model_obj, "period")

I couldn’t find or see an answer in the translateion documentation. How do I get the lazy text for the “period” field in this model and display it in a Django template?

When you define a tuple for your choices, the first value is the value to be stored in the database - the second value is what’s displayed in the selection lists. (See Choices)

If you examine your database, you should actually find the “g” as the value in the table. It’s then going to be up to you to convert that back to the full text when necessary.

Since you’re using an enumeration type for those choices, I believe you should be able to use the label attribute on the period field to get that value.

1 Like

Ah, I see, my database only contains the letters, indeed, thank you. Is there a way to get the appropriate string from the PeriodChoices class by using the letters “a” - “m”? I was able to get the translation strings using PeriodChoices.ONE.label but this means having to change ONE to TWO and so on makes it impossible for it to be used to convert “a” to “1 month”. I should be able to use something like PeriodChoices.labels[“a”].

I ended up using something questionable but it works. I used a custom template tag to translate the letters to their labels by returning:

def translate_period(period):

Translates period letters 'a' - 'm' to their translation '1 month', ...
return AssignmentAd.PeriodChoices.labels[ord(period) - 96]

It’s easier than that:


You could also create a model method to return this value directly from the model instance:

def period_label(self):
    return PeriodChoices(self.period).label
1 Like

Great stuff! Thank you