[Django]-Determine variable type within django template

4đź‘Ť

âś…

Like Ignacio Vazquez-Abrams pointed out in the first comment, that’s not really a great way to code your logic. I would ensure that your variable has a certain type. That could be solved through an additional variable you add to the context or an object that holds the data and something that describes the type of data.

If you want to stick to your logic, a possible approach would be to write your own template filter (let’s call it date_or_string). The filter could subclass the builtin date filter with the format parameter being optional. In case the parameter is passed it works like the normal date filter, without the parameter it simply returns the string. In a more complex scenario the filter could also do some type checking. Just an idea, i wouldn’t actually put that kind of logic into the template.

👤Dirk Eschler

42đź‘Ť

You could also implement a general template filter as an equivalent to the type() builtin:

# app/templatetags/util.py
from django import template

register = template.Library()

@register.filter
def get_type(value):
    return type(value)

# template.html
{% load util %}
{% if extra_column|get_type == 'str' %}
    String
{% elif extra_column|get_type == 'datetime.date' %}
    Date
{% else %}
    Oh no!
{% endif %}

I think Ignacio and Dirk are right, however. Can’t you just have two keys (you say “array”, but I assume you mean “dictionary” from the fact that the items have names) called date and detail?

# views.py
...
actions = [{
    'some_property': 'some_value'
    'date': None,
    'detail': 'details'
},
{
    'some_property': 'some_value'
    'date': datetime.date.today(),
    'detail': None
}]
...

# template.html
{% for action in actions %}
<td>{% if action.date %}{{ action.date|date:"M d" }}{% endif %}{{ action.detail }}</td>
{% endfor %}

# output
<td>details</td>
<td>Aug 19</td>
👤supervacuo

3đź‘Ť

Late to the party, but I just had this problem. The solution I went for is duck-typing, so:

{% if action.extra_column.year %}
  {{ action.extra_column|date:"M y" }}
{% else %}
  {{ action.extra_column }}
{% endif %}

Could you argue that this is definitely not the right way to do it? Probably. Will it get the job done without writing your own template filter and having even more code to maintain? Absolutely.

👤Manuel Ebert

2đź‘Ť

I know I’m way behind on this (by three years) but I just got here looking to do something similar and came up with what I think is a decent solution.

Just add a function to your models like get_model_type and have it return something you’d expect from each model like so:

class MyModelOne(models.Model):
  date_created = models.DateTimeField(auto_now_add=True)
  first_name = models.CharField(max_length=255)
  def get_model_type(self):
    return "my_model_one"

class MyModelTwo(models.Model):
  date_created = models.DateTimeField(auto_now_add=True)
  other_field = models.CharField(max_length=255)
  def get_model_type(self):
    return "my_model_two"

Then in your template you can easily just call that function:

{% if model.get_model_type == 'my_model_one' %}
  <p>Model One</p>
{% elif model.get_model_type == 'my_model_two' %}
  <p>Model Two</p>
{% endif %}
👤cardonator

1đź‘Ť

That’s my approach:

@register.filter
def get_type(value):
    """ It returns variable type as a pure string name """
    return type(value).__name__
👤Pol Clota

0đź‘Ť

You can try this to recognize String vs List type:

{%if v_1.0.1|length == 0%}
    <!--STR-->
    {{v_1}}
{%else%}     
     <!--List-->                                           
    {{v_1.0}}
{%endif%}

Leave a comment