Created
October 24, 2022 07:09
-
-
Save devvspaces/94b5331a903fb7d9aa41105a2d256beb to your computer and use it in GitHub Desktop.
Mixin to monitor changes on model fields, and call a function when a change is detected
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from typing import Callable, Dict, List | |
from django.db import models | |
class ModelChangeFunc(models.Model): | |
""" | |
Mixin to monitor changes on model fields, | |
and call a function when a change is detected | |
Setup: | |
1. Add a dict to the model with the fields to monitor | |
2. Add a function to the dict with the field name as key | |
Example: | |
```python | |
class Model(ModelChangeFunc): | |
field = models.CharField(max_length=100) | |
check = None | |
def check_field(self): | |
self.check = True | |
monitor_change = { | |
'field': check_field, | |
} | |
``` | |
Every time `field` is changed, the function `check_field` will be called | |
""" | |
class Meta: | |
abstract = True | |
# Key and Update function to run when something changes | |
monitor_change: Dict[str, Callable[..., None]] = None | |
@property | |
def monitor_change_fields(self) -> List[str]: | |
""" | |
Get all fields to monitor | |
""" | |
if self.monitor_change: | |
return list(self.monitor_change.keys()) | |
return [] | |
@property | |
def monitor_change_funcs(self) -> List[Callable[..., None]]: | |
""" | |
Get all functions to run when a field is changed | |
""" | |
if self.monitor_change: | |
return list(set(self.monitor_change.values())) | |
return [] | |
def get_clone_field(self, name: str) -> str: | |
""" | |
Get the clone field name for a field | |
""" | |
return f"__{name}" | |
def get_attr(self, field: str): | |
""" | |
Get the value of a field | |
""" | |
return getattr(self, field, None) | |
def call_updates(self): | |
"""Forcefully call all update functions""" | |
for function in self.monitor_change_funcs: | |
function(self) | |
def save(self, force_insert=False, force_update=False, *args, **kwargs): | |
""" | |
Save the model and call update functions if needed | |
""" | |
if self.pk: | |
for field in self.monitor_change_fields: | |
clone_field = self.get_clone_field(field) | |
if self.get_attr(field) != self.get_attr(clone_field): | |
self.monitor_change[field](self) | |
super().save(force_insert, force_update, *args, **kwargs) | |
for field in self.monitor_change_fields: | |
clone_field = self.get_clone_field(field) | |
default_value = self.get_attr(field) | |
setattr(self, clone_field, default_value) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
tests for it