You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

92 lines
3.6 KiB

# -*- coding: utf-8 -*-
# © 2016 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import logging
from openerp import models
_logger = logging.getLogger(__file__)
# TODO: this should be a helper module to cetralize the point of failure
# in case this introduces tacit bugs
class BasePatchModelsMixin(models.AbstractModel):
"""
This is a mixin class meant to simplify working with patches
on BaseModel or on abstract models like mail.thread.
If you just change them, models created earlier will lack the
attributes you add. Just inherit from this mixin, it will check
which existing models need your changes and apply them.
In your module, do something like
class MailThread(models.AbstractModel):
_name = 'mail.thread'
_inherit = ['base.patch.models.mixin', 'mail.thread']
in case you need to patch BaseModel, say
class BaseModel(models.BaseModel):
_name = 'my.unique.model.name'
_inherit = 'base.patch.models.mixin'
Your code will behave as if it was an inherited class of the class you pass
in the second parameter to _base_patch_models.
"""
_name = 'base.patch.models.mixin'
def _base_patch_models(self, cr, our_class=None, parent_class=None):
"""iterate through existing models to apply our changes there if
necessary"""
if self._name == BasePatchModelsMixin._name:
return
my_bases = self.__class__.__bases__
for i in range(max(len(my_bases) - 1, 0)):
if my_bases[i]._name == BasePatchModelsMixin._name:
our_class = my_bases[i - 1]
parent_class = my_bases[i + 1]
inherit = [self._inherit]\
if isinstance(self._inherit, basestring) else self._inherit
for i in range(len(my_bases) - 1, 0, -1):
# this can be different from the above if our mixin is used
# multiple times on the same model
if my_bases[i]._name in inherit:
parent_class = my_bases[i]
break
if self.__class__.__bases__[-1] == BasePatchModelsMixin\
and not our_class or not parent_class:
our_class = self.__class__.__bases__[-2]
parent_class = models.BaseModel
if not our_class or not parent_class:
_logger.info(
'Failed to autodetect own class or parent class for %s, '
'ignoring', self._name)
return
for model_name, model_object in self.pool.models.iteritems():
if not isinstance(model_object, parent_class):
continue
if isinstance(model_object, our_class):
continue
if not isinstance(model_object, models.Model):
continue
bases = list(model_object.__class__.__bases__)
position = 1
if parent_class == models.BaseModel:
position = len(bases)
else:
for i in range(len(bases) - 1, position, -1):
if bases[i]._name in inherit:
position = i
break
bases.insert(position, our_class)
model_object.__class__.__bases__ = tuple(bases)
def _register_hook(self, cr):
self._base_patch_models(cr)
for base in self.__class__.__bases__:
if not hasattr(super(base, self), '_register_hook'):
return
if super(base, self)._register_hook != self._register_hook:
return super(base, self)._register_hook.__func__(
super(base, self), cr)