Django Template Tag for Boolean Value

2.3k views Asked by At

I'm new to Django, and I'm stuck on a template tag that I can't figure out how to get working. I know I'm missing something in my view but I have written it in several different ways and can't seem to find the right way to do this. I have a Morris chart in my app that I am trying to provide information to. I want to show the percentage of operators that are available. In my model, I have a Boolean value that says if the operator is_available. When I pass it back to the template I want the template tag to run the percentage and pass back the value to the morris pie chart.

Here is my view:

    @login_required(login_url='login/')
    def operator(request):
        operators = Operator.objects.all()
        operator_status = Operator.objects.values_list('is_available', flat=True)
        context = {
            'operators': operators,
            'operators_available': operator_status,
        }
        return render(request, 'content/operator.html', context)

This is the template tag in use:

<div class="widget-detail-1">
 <h2 class="p-t-10 m-b-0"> {{ operators_available | percentage_of:True }} </h2>
 </div>
</div>

and finally my template tag:

@register.filter(name='percentage_of')
def percentage_of(part, whole):
    try:
        return "%d"[2:] % (float(part) / whole * 100)
    except (ValueError, ZeroDivisionError):
        return "Division by Zero"
2

There are 2 answers

0
Marcus Lind On

Its still a bit confusing what you actually want to achieve and how your Operators model actually look like and what values your variables contain. But I will try to make some guesses of what you want to do and try to give you an answer.

It seems as if you mix together the use of operators and operators_available and also you mix the usage of data types such as floats and booleans.

Lets go through your code...

# This returns all Model Instances of Operators. 
operators = Operator.objects.all()
# This only returns a list of Booleans. E.g. [True, True, False, True, True]
operator_status = Operator.objects.values_list('is_available', flat=True)

In your Template you write the following

<h2 class="p-t-10 m-b-0"> {{ operators_available | percentage_of:True }} </h2>

This equals to a function call of percentage_of(operators_available, True). Remember also that operators_available comes from your .valus_list('is_available') and is a boolean. So what you're actually doing is something like percentage_of(True, True).

Inside percentage_of you then try to apply math to these boolean values with (float(part) / whole * 100), or actually more like float(True) / True * 100.

The Solution

Make sure that the values that you pass to the context is in the format you expect it to. It currently look like you think that you're passing float values, but actually are passing boolean values. Try to debug or print the values before applying your template tag to them.

0
birophilo On

Your operators and operator_status variables need to be numbers as per Marcus Lind's answer: in your code, operators variable is a queryset of Operator objects, while operator_status is a list. The easiest way to get your code to work is:

operators = Operator.objects.count()
operator_status = Operator.objects.filter(is_available=True).count()

And in your template you need to pass in these two arguments to your custom filter (part and whole):

{{ operators_available|percentage_of:operators }}

Also I don't think you want the [2:] in the string formatting as your * 100 has already turned the number into a percentage.