Django 模型:无法实例化信号中的自定义字段

问题描述 投票:0回答:1

我有以下型号:

class SrdRevisionWording(ModelDiff):
    srd_revision = models.ForeignKey(SrdRevision, on_delete=models.CASCADE)
    word = models.CharField(max_length=50, null=False)
    designation = models.CharField(max_length=200, null=False)
    is_list = models.BooleanField(null=False, default=False)
    parent_element = models.IntegerField(null=True) # ID of the Wording element in the previous SRD Revision
    __original_instance = None
    with_signal = True

    def get_revision_history_message(self, created=False, deleted=False, updated_field=None, check_history=False):
        if created:
            return 'Word "{}" added'.format(self.word)

        if deleted:
            return 'Word "{}" deleted'.format(self.word)

        match updated_field:
            case 'word':
                return 'Word {} changed to {}'.format(self.__original_instance.word, self.word)
            case 'designation' | 'is_list':
                return 'Word {} modified'.format(self.word)

属性

__original_instance
是自定义模型字段(不在数据库中)。 该属性在
pre_save
信号期间实例化:

@receiver(pre_save, sender=SrdRevisionDocument)
@receiver(pre_save, sender=SrdRevisionWording)
def model_pre_save_handler(sender, instance, **kwargs):
    print('pre_save')
    if instance.srd_revision.revision != 'A':
        try:
            previous_srd_revision_state = sender.objects.get(pk=instance.parent_element)
        except sender.DoesNotExist:
            instance.__original_instance = None
        else:
            instance.__original_instance = previous_srd_revision_state
        print(instance.__original_instance)

print(instance.__original_instance)
很好地向我展示了物体
SrdRevisionWording object (21)
。 我还可以在
post_save
信号中打印对象:

@receiver(post_save, sender=SrdRevisionDocument)
@receiver(post_save, sender=SrdRevisionWording)
def handle_revision_history_element_changed(sender, instance, **kwargs):
    print('signal')
    print(instance.__original_instance)
    if instance.with_signal is not False:
       message = instance.get_revision_history_message(created=True, check_history=True)

调用

instance.get_revision_history_message()
时,问题出现在最后一行。 我在 models.py 文件中收到以下错误:

return 'Word {} changed to {}'.format(self.__original_instance.word, self.word)
                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'word'

我认为这更多是我自己对OOP的误解。但是有人可以解释一下为什么 __original_instance 似乎无法在这里为 Model 方法实例化/访问吗?

python django oop django-models
1个回答
0
投票

因为在 post_save 信号处理程序中调用 get_revision_history_message 时,__original_instance 属性为 None。发生这种情况是因为 post_save 信号不保留 pre_save 信号中设置的 __original_instance 的状态。要解决这个问题,您可以使用 Django 的 instance._state.adding 属性来确定是否正在创建实例并相应地处理逻辑。

例如:你可以这样通勤......

class SrdRevisionWording(ModelDiff):
srd_revision = models.ForeignKey(SrdRevision, on_delete=models.CASCADE)
word = models.CharField(max_length=50, null=False)
designation = models.CharField(max_length=200, null=False)
is_list = models.BooleanField(null=False, default=False)
parent_element = models.IntegerField(null=True)  # ID of the Wording element in the previous SRD Revision
__original_instance = None
with_signal = True

def set_original_instance(self):
    if self.srd_revision.revision != 'A':
        try:
            self.__original_instance = SrdRevisionWording.objects.get(pk=self.parent_element)
        except SrdRevisionWording.DoesNotExist:
            self.__original_instance = None

这种方法将有助于维持状态。

© www.soinside.com 2019 - 2024. All rights reserved.