2

I'm creating a timesheet app for logging user tasks. This is the Timesheet model:

class Timesheet(models.Model):
    date = models.ForeignKey(
        'Attendance',
        on_delete=models.CASCADE
    )
    start_time = models.TimeField()
    duration = models.DurationField()
    task = models.CharField(max_length=20)

I need to a way to update a task through a PUT request after several tasks had been created. The problem is that the start_time of a task depends on the start_time and duration of the previous tasks. So if I want to change the duration of a task, I'll need to change the start_time of all the tasks that came after it.

How do I achieve this? I'm currently using the generic view class RetrieveUpdateDestroyAPIView for the TimesheetDetail view. Should I override the put() or update() method?

Alvin
  • 59
  • 1
  • 6
  • 1
    You can override [`save()`](https://docs.djangoproject.com/en/dev/ref/models/instances/#saving-objects) at your model to achieve the desired behaviour. Overriding `put()` isn´t necessary. You can do it at `create()` / `post()` in your view too. – Klim Bim Jun 15 '21 at 06:50
  • 1
    Maybe that helps for a better understanding. [django-override-save-for-model](https://stackoverflow.com/questions/4269605/django-override-save-for-model) – Klim Bim Jun 15 '21 at 06:56
  • Isn’t save() just for updating an object? I need to update several at once. – Alvin Jun 15 '21 at 07:09
  • 1
    No, not at all. If you do `ts = Timesheet(**kwargs)` and `ts.save()` you create a new dataset and don´t update an existing one. However, you can add extra behaviour when you are creating a new object. After creating a new dataset you can alter your previous tasks. If you prefer updating previous tasks in your `post`-method, you can do it there. I prefer doing things in views/serializer and avoid overriding model-methods. – Klim Bim Jun 15 '21 at 08:26
  • 1
    Sorry, I was a little bit confused. You can override `update` at `TimeSheepDetail` to. You should retrieve e.g. `qs = Timesheep.objects.filter(start_time__lt=instance.start_time)` and update their start_time. For instance, loop over a `QuerySet`. Assign new `start_time=start_time+extra_time` and save it. – Klim Bim Jun 15 '21 at 08:51

1 Answers1

0

I followed @Klim Bim original suggestion and decided to override the save() method in the Timesheet model, since I would like to ensure consistency at every creation/update.

def save(self, *args, **kwargs):
    super().save(*args, **kwargs)

    queryset = Timesheet.objects.filter(
        date=self.date,
        start_time__gt=self.start_time
    ).order_by('start_time')

    corrected_time = (
        datetime.combine(date.today(), self.start_time) + self.duration
    ).time()

    for obj in queryset:
        obj.time = corrected_time
        corrected_time = (
            datetime.combine(date.today(), obj.start_time) + obj.duration
        ).time()
        super(Timesheet, obj).save()
Alvin
  • 59
  • 1
  • 6