Django Model : не удается инстанцировать пользовательское поле в сигнале
У меня следующая модель:
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'
Я думаю,
что это больше от моего непонимания ООП. Но может ли кто-нибудь объяснить мне, почему __original_instance кажется не инстанцированным/доступным для метода Model здесь?Потому что атрибут __original_instance равен None при вызове get_revision_history_message в обработчике сигнала post_save. Это происходит потому, что сигнал post_save не сохраняет состояние __original_instance, заданное в сигнале pre_save. Чтобы решить эту проблему, вы можете использовать свойство instance._state.adding в Django, чтобы определить, создается ли экземпляр, и обработать логику соответствующим образом.
Например: Вы можете использовать такой вариант.....
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
Этот подход будет работать на поддержание состояния.