I was planning to write a basic clock-in/clock-out app for worktime tracking using Django. Right now my code works (start/stop a shift or do pauses), but I don't use any ModelForms or ModelManagers. All business code is inside my views and a services.py file, this doesn't seem to be the correct way.
I tried to read into ModelManagers and ModelForms, but I think it just confused the hell out of me.
Let's say I have a model WorkTime:
class WorkTime(models.Model):
employee = models.ForeignKey(User)
created_at = models.DateTimeField(auto_now_add=True)
shift_started = models.DateTimeField()
shift_finished = models.DateTimeField(blank=True, null=True)
shift_duration = models.DurationField(blank=True, null=True)
work_reason = models.TextField(null=True)
I now want to have two possibilities:
As my code is right now, it's not a real beauty and definitely not DRY. How can I solve the problem the most clever way, like defining ONE ModelForm that fits all possible cases (Just start a new shift, end a running shift (only by accessing views in the browser) or add a whole shift manually with a HTML-form). Or would I split it up into having a ModelManager that does the shift starting/stopping part and a ModelForm for the manual addition of shits as an actual HTML-form?
Changing shift start and stop time simply by entering some URL via normal GET request is not an good idea. Browsers can cache that requests or fire that requests more than one (there is no pop-up when refreshing page that it can perform operation twice, like on POST requests). So you should better change that to POST requests.
For all of that views you can of course use one ModelForm
:
class SiftForm(forms.ModelForm):
class Meta:
model = WorkTime
fields = ('created_at', 'shift_started', 'shift_finished') # you shouldn't pass user and duration time here
class ShiftStartView(CreateView):
model = WorkTime
form_class = ShiftForm
success_url = "some_url" # after creating WorkTime, view will redirect to that url. You can (and really should) pass reverse_lazy() here, instead of URL as string, if you don't want to hardcode URL.
def dispatch(self, request, *args, **kwargs):
# if you want to prevent creating 2 started but not stopped WorkTimes for one user, you should put logic preventing it here.
return super(ShiftStartView, self).dispatch(self, request, *args, **kwargs)
def form_valid(self, form):
worktime = form.save(commit=False)
worktime.employee = self.request.user
worktime.save()
return super(ShiftStartView, self).form_valid(form)
That way you can create also forms for creating WorkTime
by hand. For creating stop view, you should use UpdateView
and get current WorkTime
for user in get_object
method.