Reputation: 380
I am using Django 1.10.7 and Python 3.6.1. First my code, then my questions.
My model looks like this:
class Thing(models.Model):
user = models.ForeignKey('auth.User')
title = models.CharField(max_length=200)
start_date = models.DateTimeField(
default=timezone.now)
cost_per_day = models.DecimalField(max_digits=6, decimal_places=2)
Here are my views:
def something_list(request):
things =Thing.objects.filter(start_date__lte=timezone.now()).order_by('start_date')
return render(request, 'myApp/something_list.html', {'things': things})
def thing_detail(request, pk):
thing = get_object_or_404(Thing, pk=pk)
return render(request, 'myApp/thing_detail.html', {'thing': thing})
I have two template blocks for each of these views, where I am using template tags to display variables. For example:
<h2 class="title"><a href="{% url 'thing_detail' pk=thing.pk %}">{{ thing.title }}</a></h2>
<p>User: {{ thing.user }}</p>
<div class="date">
<p>Start Date: {{ thing.start_date }}</p>
</div>
<p>Cost per day: ${{ thing.cost_per_day }}</p>
So what is happening here?
Web users can enter what I am calling any number of "Things" with 4 fields: User, Title, Start Date, and Cost per Day. I have TWO calculations that I would like to make, and render them in the template.
Problem 1) The user needs to see how many days have elapsed since they originally entered a Start Date. The calculation will be a subtraction of the current time/date (Now) and the Start Date. I was able to accomplish this by using the Django timesince feature shown here:
<button type="button" class="btn btn-info">{{ thing.quit_date|timesince }}</button>
This renders how many days and hours have elapsed - lets call it 'time elapsed' - perfectly. The problem lies in my next calculation.
Problem 2) I need to display a calculation of 'time elapsed' (shown above) multiplied by the Cost per Day variable in the current Model instance. Just for clarity, let's say the start date was 30.5 days ago, and the cost per day is $5.00. I need to multiply 30.5 by $5.00. I would love to simply multiply template tags but I understand that's not how it works. For example:
{{ thing.quit_date|timesince }} * {{ thing.cost_per_day }}
Is there a way to capture the result of this timesince calculation... {{ thing.quit_date|timesince }}... as a variable? I may not be able to use the timesince feature for this calculation.
Once again, what I ultimately need to do here is to multiply the "time elapsed" by the cost per day, like this: (Time Now - Start Date) * (Cost Per Day).
I don't know how to do this in models.py or views.py. I'm looking for the best practice way to do this using Django and Python 3.6. I'm a newbie and I have searched all day for an answer to my particular problem.
Thanks in advance and please let me know if I need to provide more information!
UPDATE
Here is my updated model based on suggestions, albeit not working (the timesince property needs work):
from django.db import models
from django.utils import timezone
from datetime import datetime
class Thing(models.Model):
quitter = models.ForeignKey('auth.User')
title = models.CharField(max_length=200)
quit_date = models.DateTimeField(default=timezone.now)
cost_per_day = models.DecimalField(max_digits=6, decimal_places=2)
notes = models.TextField()
@property
def timesince(self):
"Time since quit date"
now = datetime.now()
then = self.quit_date
return (now - then)
@property
def savings(self):
"Savings since quitting"
return self.timesince * self.cost_per_day
Here is my updated template:
<h4>Here are some calculations for this information...</h4>
<p>Days since you quit:</p>
<button type="button" class="btn btn-info">{{ thing.timesince }}</button>
<hr>
<p>How much money you have saved:</p>
<button type="button" class="btn btn-info">{{ thing.savings }}</button>
I'm certain the problem lies in the subtraction of the dates. Any insight into that would be very helpful. The template variables {{ }} are working, but there is a missing piece in the model.
By the way, when I concatenated "days" to any datetime variable, it game me errors saying .days it gave me errors. Perhaps there is an issue using both a DateTimeField and a datetime.now() instance?
Upvotes: 1
Views: 833
Reputation: 380
Here is an answer that works. I think the problem was that I was using "datetime.now()" instead of "timezone.now()". This might not be the best way of approaching this in Django/Python. I'd appreciate comments on how to make it "best practice". I really appreciate the assistance on this one!
@property
def timesince(self):
"Time since quit date"
now = timezone.now()
then = self.quit_date
return (now - then).days
@property
def savings(self):
"Savings since quitting"
return self.timesince * self.cost_per_day
Upvotes: 0
Reputation: 1507
This really isn't what template tags are for, at all. They're meant to display variables and call it a day, with some minor functional utility bolted on.
For your equations, best practice would be to implement them in the model.
from datetime import datetime
class Thing(models.Model):
quit_date = models.DateTimeField()
cost_per_day = models.FloatField() ???
@property
def timesince(self):
# Time since last whatever
elapsed = datetime.now() - self.quit_date
return elapsed.days
@property
def calculate_cost(self):
return self.timesince * self.cost_per_day
Then you can just display each of the values using {{ thing.timesince }}
and {{ thing.calculate_cost }}
in the template.
Upvotes: 1
Reputation: 3326
I would recommend creating a property on the model itself to calculate this. Subtracting the quit date from the current date will give you a timedelta
object. From there we can get the days and take it times the cost.
from django.utils import timezone
class Thing(models.Model):
...
@property
def cost(self):
days = (timezone.now().date() - self.quit_date).days
return days * self.cost_per_day
Then your template becomes very simple.
{{ thing.cost }}
Upvotes: 2