Reputation: 46
# models.py
class Appointment(models.Model):
# not including some model fields and instead focusing on the model fields that are of concern
records_sent = models.BooleanField(default=False)
record_sent_date = models.DateTimeField(blank=True, null=True)
records_received = models.BooleanField(default=False)
record_received_date = models.DateTimeField(blank=True, null=True)
# views.py
class AppointmentUpdateView(UpdateView):
model = Appointment
fields = ['records_sent', 'records_received']
def form_valid(self, form):
""" Update sent/received datetimes to current time
when sent/received is checked from false to true.
"""
appointment = self.object
if form.instance.records_sent:
appointment.records_sent_date = timezone.now()
if form.instance.records_received:
appointment.records_received_date = timezone.now()
return super().form_valid(form)
My main concern has to do with my if-statement logic in my Class View's form_valid method. Currently, if my BooleanFields are checked True via POST request, the timezone updates to now(), which is fine. But let's say I set records_sent=True on 2:00 pm. If I set records_received=True on 4:00 pm, records_sent ALSO updates its time to 4:00 pm because the POST request sent records_sent AND records_received = True in the form, subsequently triggering the if-statement again when it should be only applying to records_received.
How can I make it so that datetime.now() triggers ONLY when booleanfield is set from False to True, rather than having it also trigger from True to True?
Upvotes: 1
Views: 640
Reputation: 2110
One way is to save your status before changing in your model class attributes and __init__
can help you like following codes:
class Appointment(models.Model):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.b_records_sent = self.records_sent
self.b_records_received = self.records_received
records_sent = models.BooleanField(default=False)
record_sent_date = models.DateTimeField(blank=True, null=True)
records_received = models.BooleanField(default=False)
record_received_date = models.DateTimeField(blank=True, null=True)
and then you should add some extra conditions to form_valid
method of your form to something like:
class AppointmentUpdateView(UpdateView):
model = Appointment
fields = ['records_sent', 'records_received']
def form_valid(self, form):
""" Update sent/received datetimes to current time
when sent/received is checked from false to true.
"""
appointment = self.object
if form.instance.records_sent and appointment.b_records_sent != form.instance.records_sent:
appointment.records_sent_date = timezone.now()
if form.instance.records_received and appointment.b_records_received != form.instance.records_received:
appointment.records_received_date = timezone.now()
return super().form_valid(form)
This way the date time fields saves to table only if your boolean fields change but if you only want to save the time just once (i.e. whenever it's status changes to True) you can do something like following:
class AppointmentUpdateView(UpdateView):
model = Appointment
fields = ['records_sent', 'records_received']
def form_valid(self, form):
""" Update sent/received datetimes to current time
when sent/received is checked from false to true.
"""
appointment = self.object
if form.instance.records_sent and appointment.record_sent_date is None:
appointment.records_sent_date = timezone.now()
if form.instance.records_received and appointment.record_received_date is None:
appointment.records_received_date = timezone.now()
return super().form_valid(form)
Upvotes: 0
Reputation: 472
You shouldn't use validators for this logic, and it isn't view's logic at all. Do it with the model's power. You can handle it with the extended save method or the better way is using the signal.
@receiver(pre_save, sender=Appointment)
def update_dates(sender, instance, **kwargs):
if instance.pk: # if instance is already exist
now = timezone.now()
obj = sender._default_manager.get(pk=instance.pk)
if instance.records_sent and not obj.records_sent:
instance.records_sent_date = now
if instance.records_received and not obj.records_received:
instance.records_received_date = now
This way guarantees the dates will be updated anytime when booleans will be changed to True, even if you changed the values via the admin panel, or shell, or another way.
Upvotes: 2
Reputation: 38962
Compare the form field to the model instance field to determine if the field wasn't set already.
if not appointment.records_sent and form.instance.records_sent:
appointment.records_sent_date = timezone.now()
if not appointment.records_received and form.instance.records_received:
appointment.records_received_date = timezone.now()
return super().form_valid(form)
Upvotes: 0