se adiciona @fields.on_change para ejecutar funcion cuando se cambian los varoles de algun attributo
FossilOrigin-Name: bee19b201f8c1a6b972c2a9abfe5fb57a558a67be6ecddce4f7f07b5b6980215
This commit is contained in:
		| @@ -1,4 +1,5 @@ | |||||||
| from .fields import Field | from .fields import Field | ||||||
|  | from collections import defaultdict | ||||||
|  |  | ||||||
| class ModelMeta(type): | class ModelMeta(type): | ||||||
|     def __new__(cls, name, bases, ns): |     def __new__(cls, name, bases, ns): | ||||||
| @@ -20,6 +21,19 @@ class ModelBase(object, metaclass=ModelMeta): | |||||||
|         obj._fields = {} |         obj._fields = {} | ||||||
|         obj._text = "" |         obj._text = "" | ||||||
|         obj._namespace_prefix = None |         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 |         # forzamos registros de campos al modelo | ||||||
|         # al instanciar |         # al instanciar | ||||||
| @@ -28,6 +42,11 @@ class ModelBase(object, metaclass=ModelMeta): | |||||||
|                 if hasattr(v, 'default') and v.default is not None: |                 if hasattr(v, 'default') and v.default is not None: | ||||||
|                     setattr(obj, key, v.default) |                     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 |         return obj | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,3 +6,15 @@ from .virtual import Virtual | |||||||
| from .field import Field | from .field import Field | ||||||
|  |  | ||||||
| __all__ = [Attribute, Many2One, Model, Virtual, 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 | ||||||
|   | |||||||
| @@ -16,4 +16,6 @@ class Attribute(Field): | |||||||
|     def __set__(self, inst, value): |     def __set__(self, inst, value): | ||||||
|         assert self.name is not None |         assert self.name is not None | ||||||
|         self.value = value |         self.value = value | ||||||
|  |          | ||||||
|  |         self._changed_field(inst, self.name, value) | ||||||
|         inst._set_attribute(self.name, self.attribute, value) |         inst._set_attribute(self.name, self.attribute, value) | ||||||
|   | |||||||
| @@ -39,3 +39,8 @@ class Field: | |||||||
|             self._set_namespace(obj, self.namespace, inst.__namespace__) |             self._set_namespace(obj, self.namespace, inst.__namespace__) | ||||||
|             inst._fields[self.name] = obj |             inst._fields[self.name] = obj | ||||||
|             return obj |             return obj | ||||||
|  |  | ||||||
|  |     def _changed_field(self, inst, name, value): | ||||||
|  |         for fun in inst._on_change_fields[name]: | ||||||
|  |             getattr(inst, fun)(name, value) | ||||||
|  |              | ||||||
|   | |||||||
| @@ -31,4 +31,5 @@ class Function(Field): | |||||||
|  |  | ||||||
|     def __set__(self, inst, value): |     def __set__(self, inst, value): | ||||||
|         inst._set_field(self.name, self.field) |         inst._set_field(self.name, self.field) | ||||||
|  |         self._changed_field(inst, self.name, value) | ||||||
|         self.field.__set__(inst, value) |         self.field.__set__(inst, value) | ||||||
|   | |||||||
| @@ -26,5 +26,6 @@ class Many2One(Field): | |||||||
|         else: |         else: | ||||||
|             inst_model._set_content(value) |             inst_model._set_content(value) | ||||||
|              |              | ||||||
|  |         self._changed_field(inst, self.name, value) | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -364,3 +364,38 @@ def test_field_inserted_default_nested_many2one(): | |||||||
|     person = Person() |     person = Person() | ||||||
|     assert '<Person><ID>ole</ID></Person>' == person.to_xml() |     assert '<Person><ID>ole</ID></Person>' == 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 '<Person react="hola+4"><Hash>hola</Hash></Person>' == 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 react="hola+4" Hash="hola"/>' == person.to_xml() | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user