I have two models Label
and AlternateLabel
. Each Label
can have multiple AlternateLabel
associated with it, that is there is ForeignKey relation between them.
class Label(models.Model):
name = models.CharField(max_length=55, blank=True, unique=True)
lower_range = models.FloatField(null=True, blank=True)
upper_range = models.FloatField(null=True, blank=True)
def __str__(self) -> str:
return f"{self.name}"
class AlternateLabel(models.Model):
name = models.CharField(max_length=55, blank=False)
label = models.ForeignKey(to=Label, on_delete=models.CASCADE)
class Meta:
unique_together =('name', 'label')
def __str__(self) -> str:
return f"{self.name}"
def __repr__(self) -> str:
return f"{self.name}"
When a Label
is created one AlternateLabel
is also created using post_save
signal.
@receiver(post_save, sender=Label)
def create_alternatelabel(sender, instance, created, **kwargs):
"""
when label is created an alternate label with name as label is also created
"""
if created:
AlternateLabel.objects.get_or_create(
name = instance.name,
label = instance
)
I also want AlternateLabel
to be updated when Label
name is updated For which I tried this
@receiver(post_save, sender=Label)
def save_alternatelabel(sender, instance, created, **kwargs):
"""
when label is saved an alternate label with name as label is also saved
"""
Label.alternatelabel_set.filter(
name=instance.name,
label = instance
).first().save()
But, on updating the Label
I am getting error None type object has not method save()
, I understand this is due to the fact that, this approach is trying to find the AlternateLable
with new Label
instance name
which doesn't exist. I have been trying to figure out a way to achieve this for hours. I would appreciate any suggestion or guidance.
Since Label
can have more than one AlternateLabel
associated with it, I cannot use .update
method. Therefore I ending up using Django pre_save
signal. When Label
is updated, its id
remains same. So before the new Label
name is saved into the database, Use instance.id
to get the original name from the database, using which you can get the fix on AlternateLabel
. Which can then be updated.
@receiver(pre_save, sender=Label)
def save_alternatelabel(sender, instance, **kwargs):
"""
when label name is updated, an alternate label name is also updated.
"""
try:# getting old label name
old_label_name = Label.objects.get(id=instance.id).name
# getting alternate_label with old label name | this will get the alternate label
# which has to be changed
alternate_label = AlternateLabel.objects.get(name = old_label_name)
# changing alternate_label.name to new name
alternate_label.name = instance.name
alternate_label.save()
except Exception as e:
print(e)
This solution is working exactly required and has no drawback to the best of my knowledge.