问题
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 of 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) :-)
回答1:
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
回答2:
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])
来源:https://stackoverflow.com/questions/4548638/django-beginner-how-to-query-in-django-orm-to-calculate-fields-based-on-dates