Home > OS >  Django: unable to make a calculation inside a template
Django: unable to make a calculation inside a template

Time:09-27

I've created a e-commerce Django application and in the back office of this application, I have a page that is supposed to show some statisctics. I'm trying to display benefits or losses. For the costs, I've created a @property in the model as following:

class Statistics(models.Model):
    """
    The Statistics model represents the statistics that can be calculated
    """
    costs_infra = models.FloatField(verbose_name="Costs Infrastructure")
    costs_salary = models.FloatField(verbose_name="Costs Salary")

    class Meta:
        verbose_name_plural = "Statistics"   

    def __str__(self):
        """Unicode representation of Statistics"""

        return " Infra costs: {}, Salary costs: {}".format(
                self.costs_infra,
                self.costs_salary
            )
    
    @property
    def calculate_costs(self):
        return self.costs_infra   self.costs_salary

For the total income, I've calculated it inside a view as following:

@group_required('Administrator', 'Manager')
def stats_home(request):

    total_users = User.objects.all().count()
    costs = Statistics.objects.all()
    subscriptions_1month = Subscription.objects.get(plan_name='1 Month')
    subscriptions_1year = Subscription.objects.get(plan_name='1 Year')
    subscriptions_3year = Subscription.objects.get(plan_name='3 Years')
    user_subscriptions_1month = UserSubscription.objects.filter(subscription=subscriptions_1month).annotate(Count('user', distinct=True)).count()
    user_subscriptions_1year = UserSubscription.objects.filter(subscription=subscriptions_1year).annotate(Count('user', distinct=True)).count()
    user_subscriptions_3years = UserSubscription.objects.filter(subscription=subscriptions_3year).annotate(Count('user', distinct=True)).count()

    income_per_subscription_1month = Subscription.objects.get(plan_name='1 Month').price * UserSubscription.objects.filter(subscription=subscriptions_1month).count()
    income_per_subscription_1year = Subscription.objects.get(plan_name='1 Year').price * UserSubscription.objects.filter(subscription=subscriptions_1year).count()
    income_per_subscription_3years = Subscription.objects.get(plan_name='3 Years').price * UserSubscription.objects.filter(subscription=subscriptions_3year).count()
    
    total_income = income_per_subscription_1month   income_per_subscription_1year   income_per_subscription_3years

    return render (request, "stats_home.html", locals())

An finally, I'm trying to make a simple calculation (total income - total costs) but I'm unable to do this inside the template, as far as I could see and my research led me.

{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% load has_group %}

{% block title %} Statistics Home {% endblock %}

{% block content %}

    <div class="card border-dark mb-4" id="profil">
        <h5 class="card-header bg-dark text-white">Total number of users subscribed to the site:</h5>
        <div class="card-body">
         {{total_users}}
        </div>
    </div>

    <div class="card border-dark mb-4" id="profil">
        <h5 class="card-header bg-dark text-white">Total number of users per subscription type:</h5>
        <div class="card-body">
        <br>1 Month: {{user_subscriptions_1month}}
        <br>1 Year: {{user_subscriptions_1year}}
        <br>3 Years: {{user_subscriptions_3years}}
        </div>
    </div>

    <div class="card border-dark mb-4" id="profil">
        <h5 class="card-header bg-dark text-white">Costs:</h5>
        <div class="card-body">
            {% for cost in costs %}
            <p>Infrastructure Costs: {{cost.costs_infra}}</p>
            <p>Salary Costs: {{cost.costs_salary}}</p>
            <p>Total Costs: {{cost.calculate_costs}}</p>
            {% endfor %}
        </div>
    </div>

    <div class="card border-dark mb-4" id="profil">
        <h5 class="card-header bg-dark text-white">  Total Income: </h5>
        <div class="card-body">
          {{total_income}}
        </div>
    </div>

    <div class="card border-dark mb-4" id="profil">
        <h5 class="card-header bg-dark text-white">  Benefits/Loss: </h5>
        <div class="card-body">
            Benefits/Loss: {{total_income - cost.calculate_costs}}
        </div>
    </div>

By doing {{total_income - cost.calculate_costs}} i get an error

Could not parse the remainder: ' - cost.calculate_costs' from 'total_income - cost.calculate_costs'

The thing is that i can get the total costs with {{cost.calculate_costs}} and the total income with {{total_income}}, but somehow i'm unable to make a simple substraction inside the template.

What would be the best way to achieve this?

CodePudding user response:

The best thing you can do is, rather than doing calculation in templates do it in views as it is recommended not to do this in templates as it will decrease the performance of the website do this instead:

views.py

variable = total_income - total_costs
context = {"variable":variable}
return render(request, "stats_home.html", locals(), context)

CodePudding user response:

Your issue is that you are trying to access cost.calculate_costs outside of loop {% for cost in costs %}. Since cost is not declared, you are getting this error. On top of that, django doesn't natively support calculation in template - reason is that it's best to keep logic entirely in views and leave only presentation in templates. There is however addition filter, but you still need to calculate total_costs.

Your solution is calculate total_profit in view:

def stats_home(request):
    ...
    total_costs = sum(cost.calculate_costs for cost in costs)
    total_profit = total_income - total_costs

    return render (request, "stats_home.html", locals())
<div class="card border-dark mb-4" id="profil">
    <h5 class="card-header bg-dark text-white"> Benefits/Loss: </h5>
    <div class="card-body">
        Benefits/Loss: {{ total_profit }}
    </div>
</div>
  • Related