【问题标题】:Update Foreignkey values using Signals in Django在 Django 中使用信号更新外键值
【发布时间】:2021-01-05 09:32:41
【问题描述】:

我有两个型号 LabelAlternateLabel。每个Label可以关联多个AlternateLabel,即它们之间存在ForeignKey关系。

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}"

当创建Label 时,还会使用post_save 信号创建一个AlternateLabel

@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
        )

我还希望 AlternateLabel 在更新 Label 名称时更新,为此我尝试了这个

@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()

但是,在更新Label 时我收到错误None type object has not method save(),我知道这是因为,这种方法试图用新的Label 实例name 找到AlternateLable不存在。几个小时以来,我一直在努力想办法实现这一目标。如有任何建议或指导,我将不胜感激。

【问题讨论】:

    标签: django django-models django-views django-signals


    【解决方案1】:

    由于Label 可以关联多个AlternateLabel,我不能使用.update 方法。因此我最终使用了 Django pre_save 信号。当Label 更新时,其id 保持不变。因此,在将新的Label 名称保存到数据库之前,使用instance.id 从数据库中获取原始名称,使用它可以修复AlternateLabel。然后可以更新。

    @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)
    

    这个解决方案完全符合要求,据我所知没有缺点。

    【讨论】:

      【解决方案2】:

      嗯,您可以通过主键访问实例的备用项。

      只需使用:

      instance.alternatelabel_set.update(name=instance.name)
      

      但我建议在 Label 上创建方法并使用它们而不是信号 在观点和形式上。 例如:

      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}"
      
          def set_name(self, name):
              self.name = name
              self.save()
              self.alternatelabel_set.update(name=name)
      

      【讨论】:

      • 我试过这个,但是当只有一个备用标签时这确实有效。但是当有多个与单个标签关联的备用标签时,我得到了集成错误
      猜你喜欢
      • 2014-11-16
      • 1970-01-01
      • 2020-08-03
      • 2021-02-11
      • 1970-01-01
      • 1970-01-01
      • 2020-11-29
      • 1970-01-01
      • 2012-09-10
      相关资源
      最近更新 更多