How to define and render Django formset for registeting hours spent on a project each day during a month?

I building a Django site where users can register their time spent working on a particular project (Time Report). In the future Time reports will be subject to approval process and possibly sources for calculating invoices to clients, but right now I struggle in setting it up in Django.

I want Time Reports to hold multiple project lines and each project line should have as many input fields as many days is in a particular month . This will allow user to register number of hours spent each day on all projects they work on. In addition each project can be presented in more than line (so user can register different tasks within the project separately, e.g. hours spent on project planning vs time spent on development).

Projects are defined separately (separate model).

I believe that I need following models to support the requirements:

from django.db import models

class TimeReport(models.Model):
    employee = models.ForeignKey('employees.Employee', on_delete=models.CASCADE)
    start_date = models.DateField() #to calculate Time Report month
    status = models.CharField(max_length=20, default='draft')

class ProjectLine(models.Model):
    time_report = models.ForeignKey('TimeReport', on_delete=models.CASCADE)
    project = models.ForeignKey('projects.Project', on_delete=models.CASCADE)
    comment = models.TextField(blank=True, null=True)

class ProjectLineDay(models.Model):
    project_line = models.ForeignKey(ProjectLine, on_delete=models.CASCADE)
    date = models.DateField()
    hours = models.DecimalField(max_digits=2, decimal_places=0) 

I want to achieve something like this (excel example):

Example of expected form in excel

I figured out that I’ll need to use Django formsets but I have no experience with those and so far I don’t know how to start.

I've tried creating Django form with dynamiccaly calculated number of days (e.g. for current month) but failed with connecting it with View logic: (I'm using django-autocomplete-light for autocomplete select)

class ProjectLineForm(forms.Form):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['project'] = forms.ModelChoiceField(queryset=Project.objects.all(), widget=autocomplete.ModelSelect2(url='projects:project-autocomplete'))
        today = datetime.date.today()
        days_in_month = calendar.monthrange(today.year, today.month)[1]
        for day in range(1, days_in_month+1):
            self.fields[f'day_{day}'] = forms.IntegerField(label=False, widget=forms.NumberInput(), required=False)
        self.fields['comment'] = forms.CharField(required=False)

ProjectLineFormset = formset_factory(ProjectLineForm, extra=1, can_delete=True, min_num=1)

I'm using Crispy Forms for form formating, so I'm also trying to figure out how to display it in like a grid.

Back to Top