Voilà j'ai les classes suivantes "arbre" et "emplacement" qui sont historisées en "evol_arbre" et "evol_emplacement". J'ai une classe "station" qui contient les emplacements qui contiennent les arbres. lorsque je modifie/crée un nouvel arbre ou un nouvel emplacement la table history ne contient que la seule modification apportée à arbre ou à emplacement. Par contre quand je modifie dans la vue station un arbre ou un emplacement, la vue historisée "arbre" ou "emplacement" contient tous les arbres et tous les emplacements de la station qu'il aient été modifié ou pas. Ma question comment n'avoir que l'arbre ou l'emplacement qui a été modifié dans la table historisée ?
Voici les classes ci-dessous : class arbre(Mapable, ModelSQL, ModelView): u'Arbres' __name__ = 'cg.arbre' _rec_name ='essence' _history = True evolution = fields.One2Many( 'cg.arbre.history', 'arbre', string=u'Évolutions', help=u'Évolutions de l\'arbre', ) station = fields.Many2One( 'cg.station', ondelete='CASCADE', string=u'Code Station', help=u'Code de la station', required = True, states=STATES, depends=DEPENDS, ) @staticmethod def default_station(): return Transaction().context.get('station') emplacement = fields.Many2One( 'cg.emplacement', ondelete='CASCADE', string=u'ID Emplacement', help=u'Identifiant de l\'emplacement de référence', required = True, states=STATES, depends=DEPENDS, ) class evol_arbre(ModelSQL, ModelView): u'Évolution d\'un arbre' __name__ = 'cg.arbre.history' date = fields.DateTime( string = u'Date', help=u'Date de création du constat ou de sa mise à jour', readonly=True, ) emplacement = fields.Many2One( 'cg.emplacement', string=u'Emplacement', help=u'Code de l\'emplacement de référence', readonly=True, ) station = fields.Many2One( 'cg.station', string=u'Code Station', help=u'Code de la station', readonly=True, ) arbre = fields.Many2One( 'cg.arbre', string=u'ID Arbre', help=u'Identifiant de l\'arbre', readonly=True, ) code = fields.Char( string = u'ID Arbre', help=u'Identifiant de l\'arbre', readonly=True, ) travaux = fields.Function( fields.One2Many( 'cg.travaux', None, string=u'Travaux', help=u'travaux', readonly=True, ), 'get_travaux', ) @classmethod def _table_query_fields(cls): Arbre = Pool().get('cg.arbre') table = '%s__history' % Arbre._table return [ 'MIN("%s".__id) AS id' % table, '"%s".id AS arbre' % table, ('MIN(COALESCE("%s".write_date, "%s".create_date)) AS date' % (table, table)), ('COALESCE("%s".write_uid, "%s".create_uid) AS user' % (table, table)), ] + ['"%s"."%s"' % (table, name) for name, field in cls._fields.iteritems() if name not in ('id', 'arbre', 'date', 'user') and not hasattr(field, 'set')] @classmethod def _table_query_group(cls): Arbre = Pool().get('cg.arbre') table = '%s__history' % Arbre._table return [ '"%s".id' % table, 'COALESCE("%s".write_uid, "%s".create_uid)' % (table, table), ] + ['"%s"."%s"' % (table, name) for name, field in cls._fields.iteritems() if (name not in ('id', 'arbre', 'date', 'user') and not hasattr(field, 'set'))] @classmethod def table_query(cls): Arbre = Pool().get('cg.arbre') return (('SELECT ' + (', '.join(cls._table_query_fields())) + ' FROM "%s__history" GROUP BY ' + (', '.join(cls._table_query_group()))) % Arbre._table, []) def get_travaux(self, name): Line = Pool().get('cg.arbre.travaux') # We will always have only one id per call due to datetime_field lines = Line.search([ ('arbre', '=', self.arbre.id), ]) return [l.id for l in lines] @classmethod def read(cls, ids, fields_names=None): res = super(evol_arbre, cls).read(ids, fields_names=fields_names) # Remove microsecond from timestamp for values in res: if 'date' in values: if isinstance(values['date'], basestring): values['date'] = datetime.datetime( *time.strptime(values['date'], '%Y-%m-%d %H:%M:%S.%f')[:6]) values['date'] = values['date'].replace(microsecond=0) return res class emplacement(Mapable, ModelSQL, ModelView): u'Emplacement' __name__ = 'cg.emplacement' _history = True station = fields.Many2One( 'cg.station', ondelete='CASCADE', string=u'Code Station', help=u'Code de la station', required = True, states=STATES, depends=DEPENDS, ) evolution = fields.One2Many( 'cg.emplacement.history', 'emplacement', string=u'Évolutions', help=u'Évolutions de l\'emplacement', states=STATES, depends=DEPENDS, ) arbres = fields.One2Many( 'cg.arbre', 'emplacement', string=u'Arbres', help=u'Arbres présents sur cet emplacement', states=STATES, depends=DEPENDS, ) class evol_emplacement(ModelSQL, ModelView): u'Évolution d\'un emplacement' __name__ = 'cg.emplacement.history' date = fields.DateTime( string = u'Date de création', help=u'Date de création ou de mise à jour du constat', readonly=True, ) station = fields.Many2One( 'cg.station', string=u'Code Station', help=u'Code de la station', readonly=True, ) emplacement = fields.Many2One( 'cg.emplacement', string=u'Emplacement', help=u'Emplacement', readonly=True, ) arbres = fields.Function( fields.One2Many( 'cg.arbre', 'emplacement', string=u'Arbres', help=u'Arbres présents sur cet emplacement', ), 'get_arbres', ) @classmethod def _table_query_fields(cls): Emplacement = Pool().get('cg.emplacement') table = '%s__history' % Emplacement._table return [ 'MIN("%s".__id) AS id' % table, '"%s".id AS emplacement' % table, ('MIN(COALESCE("%s".write_date, "%s".create_date)) AS date' % (table, table)), ('COALESCE("%s".write_uid, "%s".create_uid) AS user' % (table, table)), ] + ['"%s"."%s"' % (table, name) for name, field in cls._fields.iteritems() if name not in ('id', 'emplacement', 'date', 'user') and not hasattr(field, 'set')] @classmethod def _table_query_group(cls): Emplacement = Pool().get('cg.emplacement') table = '%s__history' % Emplacement._table return [ '"%s".id' % table, 'COALESCE("%s".write_uid, "%s".create_uid)' % (table, table), ] + ['"%s"."%s"' % (table, name) for name, field in cls._fields.iteritems() if (name not in ('id', 'emplacement', 'date', 'user') and not hasattr(field, 'set'))] @classmethod def table_query(cls): Emplacement = Pool().get('cg.emplacement') return (('SELECT ' + (', '.join(cls._table_query_fields())) + ' FROM "%s__history" GROUP BY ' + (', '.join(cls._table_query_group()))) % Emplacement._table, []) def get_arbres(self, name): Line = Pool().get('cg.emplacement.arbre') # We will always have only one id per call due to datetime_field lines = Line.search([ ('emplacement', '=', self.emplacement.id), ]) return [l.id for l in lines] @classmethod def read(cls, ids, fields_names=None): res = super(evol_emplacement, cls).read(ids, fields_names=fields_names) # Remove microsecond from timestamp for values in res: if 'date' in values: if isinstance(values['date'], basestring): values['date'] = datetime.datetime( *time.strptime(values['date'], '%Y-%m-%d %H:%M:%S.%f')[:6]) values['date'] = values['date'].replace(microsecond=0) return res class station(Mapable, ModelSQL, ModelView): u'Stations' __name__ = 'cg.station' _rec_name = 'code' code = fields.Char( string = u'Code station', help=u'Code de la station', required = True, states=STATES, depends=DEPENDS, ) emplacement = fields.One2Many( 'cg.emplacement', 'station', string=u'Emplacements', help=u'Emplacements de la station', required=False, states=STATES, depends=DEPENDS, ) arbre = fields.One2Many( 'cg.arbre', 'station', string=u'Arbres', help=u'Arbres de la station', required=False, states=STATES, depends=DEPENDS, )