Task: Querying a model in Django ORM so that I can calculate fields based on dates. Specifically, extract months from a model.datefield and calculate values based on these months.
Example model:
class PersonProjectHours(models.Model):
project = models.ForeignKey('projects.Project')
person = models.ForeignKey('projects.Person')
rate = models.ForeignKey('PersonIncome')
work_date = models.DateField(help_text=_('Enter date'))
hours = models.IntegerField(help_text=_('Enter hours worked on this day.'))
class PersonIncome(models.Model):
person = models.ForeignKey('projects.Person')
income = models.DecimalField(help_text=_('Enter new income'), max_digits=10, decimal_places=2)
validdate = models.DateField(help_text=_('Enter date from which new income is valid.'))
In my views.py, I can extract the months and hours worked per month like this (I use a range because I couldn't figure out how to query for month in months in ORM). And I can calculate the cost o开发者_开发问答f the hours worked by the different people who worked on the project by looping through the entries in each month (just doesn't work right now because entry.rate is a unicode and I somehow can't covert it to an integer...):
for month in range(1, 13):
entries_per_month = PersonProjectHours.objects.filter(work_date__month=month)
hours = entries_per_month.aggregate(value=Sum('hours'))
cost = 0
for entry in entries_per_month:
cost = cost + (entry.hours * entry.rate)
work_per_year.append([month,hours,cost])
Just to complete this example, I loop through the entries in my templates like this:
{% for month, hours, cost in work_per_year %}
<tr>
<td>{{ month }}</td>
<td>{{ hours.value }}</td>
<td>{{ cost }}</td>
</tr>
{% endfor %}
What I have done in views.py doesn't seem very elegant, is there a better way to pull date ranges like years, months or days from datefields? And on the sidelines, how do I get entry.rate to be an integer I can calculate?
Thanks for your input! (yes, I am very new to coding, python, and django... took me a week to write this up) :-)
Here's the solution that I ultimately developed with the above input and other stackoverflow posts.
project = get_object_or_404(Project, code=pcode)
project_entries = PersonProjectHours.objects.filter(project=project)
project_years = project_entries.dates('work_date', 'year', order='DESC')
month_dict = {}
year_list = []
for year in project_years:
year_hours=0
year_costs=0
year = int(year.strftime("%Y"))
for month in range(1,13):
month_entries = project_entries.filter(work_date__year=year).filter(work_date__month=month)
hours=0
costs=0
for entry in month_entries:
hours = hours + entry.hours
costs = int(costs + (entry.hours * entry.rate.income))
year_hours= year_hours + hours
year_costs= year_costs + costs
try:
month_dict[year].append([datetime(year,month,1), hours, costs])
except KeyError:
month_dict[year] = ([[datetime(year,month,1), hours, costs]])
year_list.append([year,year_hours,year_costs])
Your date range pulling seems fine for me. entry.rate is a foreign key to the model PersonIncome. Would make no sense to multiply the hours with the pk of the PersonIncome instance.
I would add the rate field to the Person:
class Person(models.Model):
name = models.CharField(max_length=100)
rate = models.IntegerField(max_length=4)
Then you can do this in the view:
cost = cost + (entry.hours * entry.person.rate)
Whereas this assumes that a Person has always the same rate for any kind of work done. HTH
精彩评论