details: https://code.tryton.org/tryton/commit/5c2f445c099e
branch: default
user: Cédric Krier <[email protected]>
date: Wed Feb 25 09:04:03 2026 +0100
description:
Add timestamp field on ModelStorage for last modified
Closes #14202
diffstat:
modules/product_image/product.py | 2 +-
modules/product_image/tests/test_module.py | 2 +-
modules/production_work/work.py | 2 +-
modules/web_user/user.py | 3 +--
trytond/CHANGELOG | 1 +
trytond/trytond/ir/message.xml | 3 +++
trytond/trytond/ir/routes.py | 2 +-
trytond/trytond/ir/session.py | 4 ++--
trytond/trytond/model/modelsql.py | 10 +++++++++-
trytond/trytond/res/user.py | 3 +--
10 files changed, 21 insertions(+), 11 deletions(-)
diffs (150 lines):
diff -r 453652aa7ac8 -r 5c2f445c099e modules/product_image/product.py
--- a/modules/product_image/product.py Thu Feb 12 11:14:07 2026 +0100
+++ b/modules/product_image/product.py Wed Feb 25 09:04:03 2026 +0100
@@ -64,7 +64,7 @@
args['h'] = height
if index is not None:
args['i'] = index
- timestamp = int((self.write_date or self.create_date).timestamp())
+ timestamp = int(self.last_modified_at.timestamp())
args['t'] = (
base64.urlsafe_b64encode(timestamp.to_bytes(8, 'big'))
.decode().rstrip('='))
diff -r 453652aa7ac8 -r 5c2f445c099e modules/product_image/tests/test_module.py
--- a/modules/product_image/tests/test_module.py Thu Feb 12 11:14:07
2026 +0100
+++ b/modules/product_image/tests/test_module.py Wed Feb 25 09:04:03
2026 +0100
@@ -116,7 +116,7 @@
).read()
image.save()
- template.write_date = dt.datetime(2025, 1, 1) # fix timestamp
+ template.last_modified_at = dt.datetime(2025, 1, 1) # fix timestamp
self.assertRegex(
template.get_image_url(i=2),
diff -r 453652aa7ac8 -r 5c2f445c099e modules/production_work/work.py
--- a/modules/production_work/work.py Thu Feb 12 11:14:07 2026 +0100
+++ b/modules/production_work/work.py Wed Feb 25 09:04:03 2026 +0100
@@ -406,7 +406,7 @@
def set_duration(self, now):
if self.duration is None:
- self.duration = now - (self.write_date or self.create_date)
+ self.duration = now - self.last_modified_at
def set_cost(self):
if self.cost is None:
diff -r 453652aa7ac8 -r 5c2f445c099e modules/web_user/user.py
--- a/modules/web_user/user.py Thu Feb 12 11:14:07 2026 +0100
+++ b/modules/web_user/user.py Wed Feb 25 09:04:03 2026 +0100
@@ -442,8 +442,7 @@
@property
def expired(self):
now = datetime.datetime.now()
- timestamp = self.write_date or self.create_date
- return abs(timestamp - now) > self.timeout()
+ return abs(self.last_modified_at - now) > self.timeout()
@classmethod
def reset(cls, session):
diff -r 453652aa7ac8 -r 5c2f445c099e trytond/CHANGELOG
--- a/trytond/CHANGELOG Thu Feb 12 11:14:07 2026 +0100
+++ b/trytond/CHANGELOG Wed Feb 25 09:04:03 2026 +0100
@@ -1,3 +1,4 @@
+* Add timestamp field on ModelSQL for last modified
* Support Function field without getter but SQL expression
* Add support for column_<field name> method
* Use tables and Model as arguments for sql_column of the Field
diff -r 453652aa7ac8 -r 5c2f445c099e trytond/trytond/ir/message.xml
--- a/trytond/trytond/ir/message.xml Thu Feb 12 11:14:07 2026 +0100
+++ b/trytond/trytond/ir/message.xml Wed Feb 25 09:04:03 2026 +0100
@@ -65,6 +65,9 @@
<record model="ir.message" id="msg_edited_at">
<field name="text">Edited at</field>
</record>
+ <record model="ir.message" id="msg_last_modified_at">
+ <field name="text">Last Modified at</field>
+ </record>
<record model="ir.message" id="msg_record_name">
<field name="text">Record Name</field>
</record>
diff -r 453652aa7ac8 -r 5c2f445c099e trytond/trytond/ir/routes.py
--- a/trytond/trytond/ir/routes.py Thu Feb 12 11:14:07 2026 +0100
+++ b/trytond/trytond/ir/routes.py Wed Feb 25 09:04:03 2026 +0100
@@ -17,7 +17,7 @@
def get_token(record):
- return str((record.write_date or record.create_date).timestamp())
+ return str(record.last_modified_at.timestamp())
def get_config(names, section='html', default=None):
diff -r 453652aa7ac8 -r 5c2f445c099e trytond/trytond/ir/session.py
--- a/trytond/trytond/ir/session.py Thu Feb 12 11:14:07 2026 +0100
+++ b/trytond/trytond/ir/session.py Wed Feb 25 09:04:03 2026 +0100
@@ -96,7 +96,7 @@
if abs(session.create_date - now) < timeout:
if compare_digest(session.key, key):
find = True
- last_reset = session.write_date or session.create_date
+ last_reset = session.last_modified_at
else:
if find is None and compare_digest(session.key, key):
find = False
@@ -120,7 +120,7 @@
('key', '=', key),
domain or [],
], limit=1)
- timestamp = session.write_date or session.create_date
+ timestamp = session.last_modified_at
valid = abs(timestamp - now) < timeout
if not valid:
cls.delete([session])
diff -r 453652aa7ac8 -r 5c2f445c099e trytond/trytond/model/modelsql.py
--- a/trytond/trytond/model/modelsql.py Thu Feb 12 11:14:07 2026 +0100
+++ b/trytond/trytond/model/modelsql.py Wed Feb 25 09:04:03 2026 +0100
@@ -16,7 +16,7 @@
from trytond import backend, config
from trytond.cache import freeze
from trytond.exceptions import ConcurrencyException
-from trytond.i18n import gettext
+from trytond.i18n import gettext, lazy_gettext
from trytond.pool import Pool
from trytond.pyson import PYSONDecoder, PYSONEncoder
from trytond.rpc import RPC
@@ -322,6 +322,9 @@
_history = False
table_query = None
+ last_modified_at = fields.Function(fields.Timestamp(
+ lazy_gettext('ir.msg_last_modified_at')))
+
@classmethod
def __setup__(cls):
cls._table = config.get('table', cls.__name__, default=cls._table)
@@ -957,6 +960,11 @@
'Records were modified in the meanwhile')
@classmethod
+ def column_last_modified_at(cls, tables):
+ table, _ = tables[None]
+ return Coalesce(table.write_date, table.create_date)
+
+ @classmethod
@no_table_query
def create(cls, vlist):
transaction = Transaction()
diff -r 453652aa7ac8 -r 5c2f445c099e trytond/trytond/res/user.py
--- a/trytond/trytond/res/user.py Thu Feb 12 11:14:07 2026 +0100
+++ b/trytond/trytond/res/user.py Wed Feb 25 09:04:03 2026 +0100
@@ -325,8 +325,7 @@
], order=[('create_uid', 'ASC')])
def filter_(session):
- timestamp = session.write_date or session.create_date
- return abs(timestamp - now) < timeout
+ return abs(session.last_modified_at - now) < timeout
result.update(dict((i, len(list(g)))
for i, g in groupby(filter(filter_, sessions),
attrgetter('create_uid.id'))))