Have two models - Program and Segments. I need to calculate the total times in the program entry from the fields within the associated Segments. I attempted to do that by overriding the save methods, but when entering a new segment it won't update the program model entries unless I go directly into the program form and save/update it.
I am missing how to get the segment Update to cause the Program Save/Update to happen.
How do I give it the context to call the program save method within the Segment update (After the segment has been saved). Code of the models is:
from django.db import models
from django.urls import reverse
from datetime import datetime, timedelta
class Program(models.Model):
air_date = models.DateField(default="0000-00-00")
air_time = models.TimeField(default="00:00:00")
service = models.CharField(max_length=10)
block_time = models.TimeField(default="00:00:00")
block_time_delta = models.DurationField(default=timedelta)
running_time = models.TimeField(default="00:00:00")
running_time_delta = models.DurationField(default=timedelta)
remaining_time = models.TimeField(default="00:00:00")
remaining_time_delta = models.DurationField(default=timedelta)
title = models.CharField(max_length=190)
locked_flag = models.BooleanField(default=False)
deleted_flag = models.BooleanField(default=False)
library = models.CharField(null=True,max_length=190,blank=True)
mc = models.CharField(null=True,max_length=64)
producer = models.CharField(null=True,max_length=64)
editor = models.CharField(null=True,max_length=64)
remarks = models.TextField(null=True,blank=True)
audit_time = models.DateTimeField(null=True)
audit_user = models.CharField(null=True,max_length=32)
def calculate_time(self):
total_run_time_delta = timedelta(minutes=0)
for segs in self.segments.all():
total_run_time_delta += segs.length_time_delta
self.running_time_delta = total_run_time_delta
self.running_time = f"{self.running_time_delta}"
hold_time = self.block_time.strftime("%H:%M:%S")
t = datetime.strptime(hold_time,"%H:%M:%S")
self.block_time_delta = timedelta(hours=t.hour,
minutes=t.minute,seconds=t.second)
self.remaining_time_delta = self.block_time_delta - total_run_time_delta
self.remaining_time = f"{abs(self.remaining_time_delta)}"
def save(self, *args, **kwargs):
self.calculate_time()
super().save(*args,**kwargs)
def __str__(self):
return f"{self.pk} : {self.title}"
def get_absolute_url(self):
return reverse('program_detail', args=[str(self.id)])
#return reverse('program-update', kwargs={'pk': self.pk})
class Segment(models.Model):
program_id = models.ForeignKey(Program,
on_delete=models.CASCADE,
related_name='segments', #new link to Program
)
sequence_number = models.DecimalField(decimal_places=2,max_digits=6,default="0.00")
title = models.CharField(max_length=190)
bridge_flag = models.BooleanField(default=False)
length_time = models.TimeField(null=True,default=None, blank=True)
length_time_delta = models.DurationField(default=timedelta)
author = models.CharField(max_length=64,null=True,default=None,blank=True)
voice = models.CharField(max_length=64,null=True,default=None,blank=True)
library = models.CharField(max_length=190,null=True,default=None,blank=True)
summary = models.TextField()
audit_time = models.DateTimeField(null=True)
audit_user = models.CharField(null=True,max_length=32)
def save( self, *args, **kwargs):
super().save(*args,**kwargs)
return super(Program,self.program_id).save()
def __str__(self):
return f"{self.title}"
The views look like this...
class ProgramUpdateView(LoginRequiredMixin,UpdateView):
class Meta:
model = Program
widgets = {
'remarks': Textarea(attrs={'row':10, 'cols':80}),
}
model = Program
success_url = "/program/{id}/"
template_name = 'program_update.html'
fields = [
'title',
'service',
'library',
'air_date',
'air_time',
'producer',
'editor',
'mc',
'block_time',
'remaining_time',
'running_time',
'remarks',
]
def form_valid(self, form):
return super(ProgramUpdateView, self).form_valid(form)
class SegmentUpdate(LoginRequiredMixin,UpdateView):
model = Segment
fields = '__all__'
template_name = 'segment_update.html'
I originally thought I could do this all in the models, but now I am not so sure.
Thanks for any info you can provide....
try to directly call Program.save() method through the fk
in Segment model
def save( self, *args, **kwargs):
super().save(*args,**kwargs)
self.program_id.save()
or use django signals https://docs.djangoproject.com/en/3.1/topics/signals/
from django.db.models.signals import post_save, post_delete
@receiver([post_save, post_delete], sender=Segment)
def update_program(sender, instance, **kwargs):
program = Program.objects.get(pk=instance.program_id.pk)
program.save()
Please keep your database atomic. Don't save in it something that can be computed from other fields unless you have a very good reason to do it. The reason you're giving for doing it doesn't seem like a good one. You want the total time of the segments when you got a list of programs? Fine, simply annotate the querystring with a sum. You'll do it everytime? Create a custom queryset/manager that do it for you.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.