-
-
Notifications
You must be signed in to change notification settings - Fork 368
Open
Description
Setting the monitor value on the MonitorField pointing to a M2M field currently throws this exception:
"<Model: Model object (None)>" needs to have a value for field "id" before this many-to-many relationship can be used.
This is due to:
def get_monitored_value(self, instance: models.Model) -> Any:
# Trying to access the related model instance before the instance is actually saved
return getattr(instance, self.monitor)Moreover there isn't a way to get a real difference between the old and new value on a M2M field.
Since the only way I though of was to leverage the m2m_changed Django signal, I extended the field this way.
class M2MMonitorField(MonitorField):
"""Extend MonitorField to also support M2M fields.
Always set the initial value with the default.
When the `m2m_changed` signal is triggered update the monitor field.
"""
def contribute_to_class(
self,
cls: type[models.Model],
name: str,
*args,
**kwargs,
) -> None:
super().contribute_to_class(cls, name, *args, **kwargs)
models.signals.post_init.connect(self._setup_m2m_signal, sender=cls)
def get_monitored_field(self, instance: models.Model):
return instance._meta.get_field(self.monitor) # noqa: SLF001
def get_monitored_value(self, instance: models.Model):
monitored_field = self.get_monitored_field(instance)
if monitored_field.many_to_many:
return self.default
return getattr(instance, self.monitor)
def _setup_m2m_signal(
self,
sender: type[models.Model],
instance: models.Model,
**kwargs,
) -> None:
monitored_field = self.get_monitored_field(instance)
if monitored_field.many_to_many:
sender = monitored_field.remote_field.through
models.signals.m2m_changed.connect(self._save_m2m_field, sender=sender)
def _save_m2m_field(
self,
sender: type[models.Model],
instance: models.Model,
**kwargs,
) -> None:
value = timezone.now()
setattr(instance, self.attname, value)
instance.save_base(update_fields=self.attname, raw=True)This is working as expected but I'd like to hear if there are any possible flaws or room for improvements.
Metadata
Metadata
Assignees
Labels
No labels