Files
tryton/trytond/model/modelsingleton.py
T
Cédric Krier 57248f9655 Clear cache for all records of ModelSingleton
As write and delete can be called with any ids for records and the super calls
are always on the real record, the cache is only cleared for the real record.
So ModelSingleton must ensure to clear the cache for any record ids.

issue7205
review44731002
2018-03-15 00:23:11 +01:00

116 lines
4.1 KiB
Python

# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import ModelStorage
from trytond.transaction import Transaction
class ModelSingleton(ModelStorage):
"""
Define a singleton model in Tryton.
"""
@classmethod
def get_singleton(cls):
'''
Return the instance of the unique record if there is one.
'''
singletons = super(ModelSingleton, cls).search([], limit=1)
if singletons:
return singletons[0]
@classmethod
def create(cls, vlist):
assert len(vlist) == 1
singleton = cls.get_singleton()
if not singleton:
return super(ModelSingleton, cls).create(vlist)
cls.write([singleton], vlist[0])
return [singleton]
@classmethod
def read(cls, ids, fields_names=None):
singleton = cls.get_singleton()
if not singleton:
if not fields_names:
fields_names = cls._fields.keys()
fname_no_rec_name = [f for f in fields_names if '.' not in f]
res = cls.default_get(fname_no_rec_name,
with_rec_name=len(fname_no_rec_name) != len(fields_names))
for field_name in fields_names:
if field_name not in res:
res[field_name] = None
for field_name in res.keys():
if field_name not in fields_names:
del res[field_name]
res['id'] = ids[0]
return [res]
res = super(ModelSingleton, cls).read([singleton.id],
fields_names=fields_names)
res[0]['id'] = ids[0]
return res
@classmethod
def write(cls, records, values, *args):
singleton = cls.get_singleton()
if not singleton:
singleton, = cls.create([values])
actions = (records, values) + args
args = []
for values in actions[1:None:2]:
args.extend(([singleton], values))
super(ModelSingleton, cls).write(*args)
# Clean local cache of original records
for record in sum(actions[0:None:2], []):
local_cache = record._local_cache.get(record.id)
if local_cache:
local_cache.clear()
# Clean transaction cache of all ids
for cache in Transaction().cache.itervalues():
if cls.__name__ in cache:
cache[cls.__name__].clear()
@classmethod
def delete(cls, records):
singleton = cls.get_singleton()
if singleton:
super(ModelSingleton, cls).delete([singleton])
# Clean transaction cache of all ids
for cache in Transaction().cache.itervalues():
if cls.__name__ in cache:
cache[cls.__name__].clear()
@classmethod
def copy(cls, records, default=None):
if default:
cls.write(records, default)
return records
@classmethod
def search(cls, domain, offset=0, limit=None, order=None, count=False):
res = super(ModelSingleton, cls).search(domain, offset=offset,
limit=limit, order=order, count=count)
if not res and not domain:
if count:
return 1
return [cls(1)]
return res
@classmethod
def default_get(cls, fields_names, with_rec_name=True):
if '_timestamp' in fields_names:
fields_names = list(fields_names)
fields_names.remove('_timestamp')
default = super(ModelSingleton, cls).default_get(fields_names,
with_rec_name=with_rec_name)
singleton = cls.get_singleton()
if singleton:
if with_rec_name:
fields_names = fields_names[:]
for field in fields_names[:]:
if cls._fields[field]._type in ('many2one',):
fields_names.append(field + '.rec_name')
default, = cls.read([singleton.id], fields_names=fields_names)
for field in (x for x in default.keys() if x not in fields_names):
del default[field]
return default