se adiciona notificaciones de cambios para fields.One2Many
FossilOrigin-Name: b422aa912c7c7873edcbbecf1914e9ff21a24cab3fc7e2a788e00efc16fe2f51
This commit is contained in:
		| @@ -1,11 +1,46 @@ | |||||||
| from .field import Field | from .field import Field | ||||||
|  |  | ||||||
| class BoundModel: | # TODO(bit4bit) lograr que isinstance se aplique | ||||||
|     def __init__(self, creator): | # al objeto envuelto | ||||||
|  | class _RelationProxy(): | ||||||
|  |     def __init__(self, obj, inst, attribute): | ||||||
|  |         self.__dict__['_obj'] = obj | ||||||
|  |         self.__dict__['_inst'] = inst | ||||||
|  |         self.__dict__['_attribute'] = attribute | ||||||
|  |  | ||||||
|  |     def __getattr__(self, name): | ||||||
|  |         if (name in self.__dict__): | ||||||
|  |             return self.__dict__[name] | ||||||
|  |  | ||||||
|  |         return getattr(self.__dict__['_obj'], name) | ||||||
|  |  | ||||||
|  |     def __setattr__(self, attr, value): | ||||||
|  |         # TODO(bit4bit) hacemos proxy al sistema de notificacion de cambios | ||||||
|  |         # algo burdo, se usa __dict__ para saltarnos el __getattr__ y generar un fallo por recursion | ||||||
|  |         for fun in self.__dict__['_inst']._on_change_fields[self.__dict__['_attribute']]: | ||||||
|  |             fun(self.__dict__['_inst'], self.__dict__['_attribute'], value) | ||||||
|  |  | ||||||
|  |         return setattr(self._obj, attr, value) | ||||||
|  |  | ||||||
|  | class _Relation(): | ||||||
|  |     def __init__(self, creator, inst, attribute): | ||||||
|         self.creator = creator |         self.creator = creator | ||||||
|  |         self.inst = inst | ||||||
|  |         self.attribute = attribute | ||||||
|  |         self.relations = [] | ||||||
|  |  | ||||||
|     def create(self): |     def create(self): | ||||||
|         return self.creator() |         n_relations = len(self.relations) | ||||||
|  |         attribute = '%s_%d' % (self.attribute, n_relations) | ||||||
|  |         relation = self.creator(attribute) | ||||||
|  |         proxy = _RelationProxy(relation, self.inst, self.attribute) | ||||||
|  |  | ||||||
|  |         self.relations.append(relation) | ||||||
|  |         return proxy | ||||||
|  |  | ||||||
|  |     def __len__(self): | ||||||
|  |         return len(self.relations) | ||||||
|  |  | ||||||
|  |  | ||||||
| class One2Many(Field): | class One2Many(Field): | ||||||
|     def __init__(self, model, name=None, namespace=None, default=None): |     def __init__(self, model, name=None, namespace=None, default=None): | ||||||
| @@ -13,13 +48,16 @@ class One2Many(Field): | |||||||
|         self.field_name = name |         self.field_name = name | ||||||
|         self.namespace = namespace |         self.namespace = namespace | ||||||
|         self.default = default |         self.default = default | ||||||
|         self.count_relations = 0 |         self.relation = None | ||||||
|          |          | ||||||
|     def __get__(self, inst, cls): |     def __get__(self, inst, cls): | ||||||
|         assert self.name is not None |         assert self.name is not None | ||||||
|         def creator(): |  | ||||||
|             attribute = '%s_%d' % (self.name, self.count_relations) |  | ||||||
|             self.count_relations += 1 |  | ||||||
|             return self._create_model(inst, name=self.field_name, model=self.model, attribute=attribute) |  | ||||||
|  |  | ||||||
|         return BoundModel(creator) |         def creator(attribute): | ||||||
|  |             return self._create_model(inst, name=self.field_name, model=self.model, attribute=attribute) | ||||||
|  |          | ||||||
|  |         if self.relation: | ||||||
|  |             return self.relation | ||||||
|  |         else: | ||||||
|  |             self.relation = _Relation(creator, inst, self.name) | ||||||
|  |             return self.relation | ||||||
|   | |||||||
| @@ -416,3 +416,29 @@ def test_model_one2many(): | |||||||
|     line = invoice.lines.create() |     line = invoice.lines.create() | ||||||
|     line.quantity = 5 |     line.quantity = 5 | ||||||
|     assert '<Invoice><Line quantity="3"/><Line quantity="5"/></Invoice>' == invoice.to_xml() |     assert '<Invoice><Line quantity="3"/><Line quantity="5"/></Invoice>' == invoice.to_xml() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_model_one2many_with_on_changes(): | ||||||
|  |     class Line(facho.model.Model): | ||||||
|  |         __name__ = 'Line' | ||||||
|  |  | ||||||
|  |         quantity = fields.Attribute('quantity') | ||||||
|  |          | ||||||
|  |     class Invoice(facho.model.Model): | ||||||
|  |         __name__ = 'Invoice' | ||||||
|  |  | ||||||
|  |         lines = fields.One2Many(Line) | ||||||
|  |         count = fields.Attribute('count', default=0) | ||||||
|  |          | ||||||
|  |         @fields.on_change(['lines']) | ||||||
|  |         def refresh_count(self, name, value): | ||||||
|  |             self.count = len(self.lines) | ||||||
|  |  | ||||||
|  |     invoice = Invoice() | ||||||
|  |     line = invoice.lines.create() | ||||||
|  |     line.quantity = 3 | ||||||
|  |     line = invoice.lines.create() | ||||||
|  |     line.quantity = 5 | ||||||
|  |  | ||||||
|  |     assert len(invoice.lines) == 2 | ||||||
|  |     assert '<Invoice count="2"><Line quantity="3"/><Line quantity="5"/></Invoice>' == invoice.to_xml() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user