Bart P.
Bart P.

Reputation: 919

django get first part of a string

Is there a simple django tag to get the first x characters of a string in a template?

In a list of modelinstances, I would like to give a different symbol per objectinstance, depending on the status of the objectinstance. Status could be 'waiting', 'success' or 'failed XXXX', with XXXX being the errorcode.

I would like to check if the first 5 characters of objectinstance.status == 'error', then the symbol will be red. However, how can I do this? In Python I could use objectinstance.status[:5].

Using https://docs.djangoproject.com/en/dev/ref/templates/builtins/ I managed to do this with following 'monstruous' concatenation, but is there something simple as .left() or .right()?

{% if run.status|make_list|slice:":5"|join:"" == 'error' %}

Upvotes: 3

Views: 4510

Answers (2)

Anton I. Sipos
Anton I. Sipos

Reputation: 3613

You could try:

{% if run.status|truncatechars:5 == 'error...' %}

(See truncatechars in the Django docs)

Although I might say, as an overall point, you shouldn't be putting this kind of logic in your Django templates (views in other frameworks). You want to put this into the Django view (controller in other framerworks). Meaning, you would something like this in your view:

has_error = run.status.startswith('error')

Ensure has_error is passed to the template and:

{% if has_error %}

It may be more work, but the logic to detect error conditions could be shared between multiple views and templates, and you separate control logic from view logic.

Upvotes: 5

furins
furins

Reputation: 5048

If you use Django 1.4+ you can use the truncatechars tag but it will only solve partially your answer and will add ellipsis at the end.

The only viable way, a part from concatenating many filters as you already did, is to write a custom filter. Here is a first draft you can customize:

from django import template
from django.template.defaultfilters import stringfilter

register = template.Library()

@register.filter
@stringfilter
def slicestring(value, arg):
    """usage: "mylongstring"|slicestring:"2:4" """
    els = map(int, arg.split(':'))
    return value[els[0]:els[1]]

as a bonus this filter allows you to mimic almost completely the slice notation by providing a "slicing string" as the argument. The only exception seems the syntax [:9] that has to be replaced with [0:9], thus with this argument: yourvariable|slicestring:"0:9"

A side note: Since your question is "getting the first part of a string" I believe a custom filter may be the correct answer, however if the only reason to get a sliced string is to check for a part of it inside an if statement, then I have to agree with Anton: you should place your checks inside the view, not inside the template, when possible.

Upvotes: 0

Related Questions