From c694603505eca2af9d2257c3e3ecae4de40d3c8c Mon Sep 17 00:00:00 2001 From: bit4bit Date: Fri, 25 Jun 2021 23:21:04 +0000 Subject: [PATCH] se adiciona @fields.on_change para ejecutar funcion cuando se cambian los varoles de algun attributo FossilOrigin-Name: bee19b201f8c1a6b972c2a9abfe5fb57a558a67be6ecddce4f7f07b5b6980215 --- facho/model/__init__.py | 21 +++++++++++++++++++- facho/model/fields/__init__.py | 12 +++++++++++ facho/model/fields/attribute.py | 2 ++ facho/model/fields/field.py | 5 +++++ facho/model/fields/function.py | 1 + facho/model/fields/many2one.py | 3 ++- tests/test_model.py | 35 +++++++++++++++++++++++++++++++++ 7 files changed, 77 insertions(+), 2 deletions(-) diff --git a/facho/model/__init__.py b/facho/model/__init__.py index 51a9345..f64bd55 100644 --- a/facho/model/__init__.py +++ b/facho/model/__init__.py @@ -1,4 +1,5 @@ from .fields import Field +from collections import defaultdict class ModelMeta(type): def __new__(cls, name, bases, ns): @@ -20,6 +21,19 @@ class ModelBase(object, metaclass=ModelMeta): obj._fields = {} obj._text = "" obj._namespace_prefix = None + obj._on_change_fields = defaultdict(list) + + def on_change_fields_for_function(function_name): + # se recorre arbol buscando el primero + for parent_cls in type(obj).__mro__: + parent_meth = getattr(parent_cls, function_name, None) + if not parent_meth: + continue + + on_changes = getattr(parent_meth, 'on_changes', None) + if on_changes: + return on_changes + return [] # forzamos registros de campos al modelo # al instanciar @@ -28,7 +42,12 @@ class ModelBase(object, metaclass=ModelMeta): if hasattr(v, 'default') and v.default is not None: setattr(obj, key, v.default) - + # register callbacks for changes + function_name = 'on_change_%s' % (key) + on_change_fields = on_change_fields_for_function(function_name) + for field in on_change_fields: + obj._on_change_fields[field].append(function_name) + return obj def _set_attribute(self, field, name, value): diff --git a/facho/model/fields/__init__.py b/facho/model/fields/__init__.py index 4e35a11..c3f59a3 100644 --- a/facho/model/fields/__init__.py +++ b/facho/model/fields/__init__.py @@ -6,3 +6,15 @@ from .virtual import Virtual from .field import Field __all__ = [Attribute, Many2One, Model, Virtual, Field] + +def on_change(fields): + from functools import wraps + + def decorator(func): + setattr(func, 'on_changes', fields) + + @wraps(func) + def wrapper(self, *arg, **kwargs): + return func(self, *arg, **kwargs) + return wrapper + return decorator diff --git a/facho/model/fields/attribute.py b/facho/model/fields/attribute.py index 9d8677c..6adfc36 100644 --- a/facho/model/fields/attribute.py +++ b/facho/model/fields/attribute.py @@ -16,4 +16,6 @@ class Attribute(Field): def __set__(self, inst, value): assert self.name is not None self.value = value + + self._changed_field(inst, self.name, value) inst._set_attribute(self.name, self.attribute, value) diff --git a/facho/model/fields/field.py b/facho/model/fields/field.py index 6d8e523..d340bbc 100644 --- a/facho/model/fields/field.py +++ b/facho/model/fields/field.py @@ -39,3 +39,8 @@ class Field: self._set_namespace(obj, self.namespace, inst.__namespace__) inst._fields[self.name] = obj return obj + + def _changed_field(self, inst, name, value): + for fun in inst._on_change_fields[name]: + getattr(inst, fun)(name, value) + diff --git a/facho/model/fields/function.py b/facho/model/fields/function.py index 58388e5..1da5e52 100644 --- a/facho/model/fields/function.py +++ b/facho/model/fields/function.py @@ -31,4 +31,5 @@ class Function(Field): def __set__(self, inst, value): inst._set_field(self.name, self.field) + self._changed_field(inst, self.name, value) self.field.__set__(inst, value) diff --git a/facho/model/fields/many2one.py b/facho/model/fields/many2one.py index d75e03b..5134e3d 100644 --- a/facho/model/fields/many2one.py +++ b/facho/model/fields/many2one.py @@ -25,6 +25,7 @@ class Many2One(Field): setter(inst_model, value) else: inst_model._set_content(value) - + + self._changed_field(inst, self.name, value) diff --git a/tests/test_model.py b/tests/test_model.py index 1028803..532c582 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -364,3 +364,38 @@ def test_field_inserted_default_nested_many2one(): person = Person() assert 'ole' == person.to_xml() +def test_model_on_change_field(): + class Hash(facho.model.Model): + __name__ = 'Hash' + + class Person(facho.model.Model): + __name__ = 'Person' + + react = fields.Attribute('react') + hash = fields.Many2One(Hash) + + @fields.on_change(['hash']) + def on_change_react(self, name, value): + assert name == 'hash' + self.react = "%s+4" % (value) + + person = Person() + person.hash = 'hola' + assert 'hola' == person.to_xml() + +def test_model_on_change_field_attribute(): + class Person(facho.model.Model): + __name__ = 'Person' + + react = fields.Attribute('react') + hash = fields.Attribute('Hash') + + @fields.on_change(['hash']) + def on_change_react(self, name, value): + assert name == 'hash' + self.react = "%s+4" % (value) + + person = Person() + person.hash = 'hola' + assert '' == person.to_xml() +