details: https://code.tryton.org/tryton/commit/26aca1c56728
branch: default
user: Cédric Krier <[email protected]>
date: Thu Jan 29 12:42:56 2026 +0100
description:
Use tables and Model as arguments for sql_column of the Field
diffstat:
modules/account_payment/payment.py | 2 +-
modules/bank/bank.py | 2 +-
modules/country/country.py | 2 +-
modules/product_cost_fifo/move.py | 4 ++--
trytond-gis/trytond_gis/fields.py | 2 +-
trytond/CHANGELOG | 1 +
trytond/doc/ref/fields.rst | 5 +++--
trytond/trytond/model/fields/char.py | 8 ++++----
trytond/trytond/model/fields/dict.py | 6 ++----
trytond/trytond/model/fields/field.py | 14 +++++++-------
trytond/trytond/model/fields/many2many.py | 12 +++++++-----
trytond/trytond/model/fields/many2one.py | 18 +++++++++---------
trytond/trytond/model/fields/multiselection.py | 3 +--
trytond/trytond/model/fields/one2many.py | 8 ++++----
trytond/trytond/model/fields/reference.py | 3 +--
trytond/trytond/model/fields/selection.py | 3 +--
trytond/trytond/model/fields/text.py | 5 ++---
trytond/trytond/model/modelsql.py | 24 ++++++++++++++----------
18 files changed, 62 insertions(+), 60 deletions(-)
diffs (496 lines):
diff -r 0359c8ecc314 -r 26aca1c56728 modules/account_payment/payment.py
--- a/modules/account_payment/payment.py Tue Feb 10 19:30:10 2026 +0100
+++ b/modules/account_payment/payment.py Thu Jan 29 12:42:56 2026 +0100
@@ -547,7 +547,7 @@
def order_amount(cls, tables):
table, _ = tables[None]
context = Transaction().context
- column = cls.amount.sql_column(table)
+ column = cls.amount.sql_column(tables, cls)
if isinstance(context.get('amount_order'), Decimal):
return [Abs(column - abs(context['amount_order']))]
else:
diff -r 0359c8ecc314 -r 26aca1c56728 modules/bank/bank.py
--- a/modules/bank/bank.py Tue Feb 10 19:30:10 2026 +0100
+++ b/modules/bank/bank.py Thu Jan 29 12:42:56 2026 +0100
@@ -245,7 +245,7 @@
Operator = fields.SQL_OPERATORS[operator]
result = None
for field in (cls.number, cls.number_compact):
- column = field.sql_column(table)
+ column = field.sql_column(tables, cls)
expression = Operator(column, field._domain_value(operator, value))
if isinstance(expression, operators.In) and not expression.right:
expression = Literal(False)
diff -r 0359c8ecc314 -r 26aca1c56728 modules/country/country.py
--- a/modules/country/country.py Tue Feb 10 19:30:10 2026 +0100
+++ b/modules/country/country.py Thu Jan 29 12:42:56 2026 +0100
@@ -437,7 +437,7 @@
_, op, value = domain
Operator = fields.SQL_OPERATORS[op]
- column = cls.code.sql_column(table)
+ column = cls.code.sql_column(tables, cls)
if op.endswith('like'):
if op.endswith('ilike') and cls.code.search_unaccented:
database = Transaction().database
diff -r 0359c8ecc314 -r 26aca1c56728 modules/product_cost_fifo/move.py
--- a/modules/product_cost_fifo/move.py Tue Feb 10 19:30:10 2026 +0100
+++ b/modules/product_cost_fifo/move.py Thu Jan 29 12:42:56 2026 +0100
@@ -61,8 +61,8 @@
field = cls.fifo_quantity_available._field
Operator = fields.SQL_OPERATORS[operator]
column = (
- cls.quantity.sql_column(table)
- - cls.fifo_quantity.sql_column(table))
+ cls.quantity.sql_column(tables, cls)
+ - cls.fifo_quantity.sql_column(tables, cls))
expression = Operator(column, field._domain_value(operator, value))
if isinstance(expression, operators.In) and not expression.right:
expression = Literal(False)
diff -r 0359c8ecc314 -r 26aca1c56728 trytond-gis/trytond_gis/fields.py
--- a/trytond-gis/trytond_gis/fields.py Tue Feb 10 19:30:10 2026 +0100
+++ b/trytond-gis/trytond_gis/fields.py Thu Jan 29 12:42:56 2026 +0100
@@ -42,7 +42,7 @@
assert operator in GEOGRAPHIC_OPERATORS
- column = self.sql_column(table)
+ column = self.sql_column(tables, Model)
if operator in {'=', '!='} and value is Null:
Operator = SQL_OPERATORS[operator]
diff -r 0359c8ecc314 -r 26aca1c56728 trytond/CHANGELOG
--- a/trytond/CHANGELOG Tue Feb 10 19:30:10 2026 +0100
+++ b/trytond/CHANGELOG Thu Jan 29 12:42:56 2026 +0100
@@ -1,3 +1,4 @@
+* Use tables and Model as arguments for sql_column of the Field
* Add support for basic authentication for user application
* Support the conversion of MJML reports to HTML
* Allow filtering users to be notified by cron tasks
diff -r 0359c8ecc314 -r 26aca1c56728 trytond/doc/ref/fields.rst
--- a/trytond/doc/ref/fields.rst Tue Feb 10 19:30:10 2026 +0100
+++ b/trytond/doc/ref/fields.rst Thu Jan 29 12:42:56 2026 +0100
@@ -191,9 +191,10 @@
Return the SQL expression with cast with the type of the field.
-.. method:: Field.sql_column(table)
+.. method:: Field.sql_column(tables, Model)
- Return the Column instance based on table.
+ Return the Column or SQL expression instance for the field.
+ :ref:`tables <ref-tables>` could be updated to add new joins.
.. method:: Field.set_rpc(model)
diff -r 0359c8ecc314 -r 26aca1c56728 trytond/trytond/model/fields/char.py
--- a/trytond/trytond/model/fields/char.py Tue Feb 10 19:30:10 2026 +0100
+++ b/trytond/trytond/model/fields/char.py Thu Jan 29 12:42:56 2026 +0100
@@ -3,7 +3,7 @@
import string
import warnings
-from sql import Expression, Query
+from sql import Column, Expression, Query
from sql.conditionals import Coalesce, NullIf
from sql.functions import Trim
from sql.operators import Not
@@ -143,10 +143,10 @@
language = transaction.language
model, join, column = self._get_translation_column(
Model, name)
- column = Coalesce(NullIf(column, ''), self.sql_column(model))
+ column = Coalesce(NullIf(column, ''), Column(model, self.name))
else:
language = None
- column = self.sql_column(table)
+ column = self.sql_column(tables, Model)
column = self._domain_column(operator, column)
threshold = context.get(
@@ -207,7 +207,7 @@
column = self._get_translation_order(tables, Model, name)
else:
language = None
- column = self.sql_column(table)
+ column = self.sql_column(tables, Model)
column = self._domain_column('ilike', column)
if database.has_similarity():
sim_value = unescape_wildcard(value)
diff -r 0359c8ecc314 -r 26aca1c56728 trytond/trytond/model/fields/dict.py
--- a/trytond/trytond/model/fields/dict.py Tue Feb 10 19:30:10 2026 +0100
+++ b/trytond/trytond/model/fields/dict.py Thu Jan 29 12:42:56 2026 +0100
@@ -119,10 +119,9 @@
if '.' not in name:
return super().convert_domain(domain, tables, Model)
database = Transaction().database
- table, _ = tables[None]
name, key = name.split('.', 1)
Operator = SQL_OPERATORS[operator]
- raw_column = self.sql_column(table)
+ raw_column = self.sql_column(tables, Model)
column = self._domain_column(operator, raw_column, key)
expression = Operator(column, self._domain_value(operator, value))
if operator in {'=', '!='}:
@@ -171,8 +170,7 @@
if not key:
return super().convert_order(fname, tables, Model)
database = Transaction().database
- table, _ = tables[None]
- column = self.sql_column(table)
+ column = self.sql_column(tables, Model)
return [database.json_get(column, key)]
def definition(self, model, language):
diff -r 0359c8ecc314 -r 26aca1c56728 trytond/trytond/model/fields/field.py
--- a/trytond/trytond/model/fields/field.py Tue Feb 10 19:30:10 2026 +0100
+++ b/trytond/trytond/model/fields/field.py Thu Jan 29 12:42:56 2026 +0100
@@ -421,7 +421,8 @@
def sql_cast(self, expression):
return Cast(expression, self.sql_type().base)
- def sql_column(self, table):
+ def sql_column(self, tables, Model):
+ table, _ = tables[None]
return Column(table, self.name)
def _domain_column(self, operator, column):
@@ -451,7 +452,7 @@
table, _ = tables[None]
name, operator, value = domain
Operator = SQL_OPERATORS[operator]
- column = self.sql_column(table)
+ column = self.sql_column(tables, Model)
column = self._domain_column(operator, column)
expression = Operator(column, self._domain_value(operator, value))
if isinstance(expression, operators.In) and not expression.right:
@@ -464,8 +465,7 @@
@order_method
def convert_order(self, name, tables, Model):
"Return a SQL expression to order"
- table, _ = tables[None]
- return [self.sql_column(table)]
+ return [self.sql_column(tables, Model)]
def set_rpc(self, model):
for attribute, decorator, result in (
@@ -680,7 +680,7 @@
table, _ = tables[None]
name, operator, value = domain
model, join, column = self._get_translation_column(Model, name)
- column = Coalesce(NullIf(column, ''), self.sql_column(model))
+ column = Coalesce(NullIf(column, ''), Column(model, self.name))
column = self._domain_column(operator, column)
Operator = SQL_OPERATORS[operator]
assert name == self.name
@@ -731,9 +731,9 @@
if not self.translate:
return super().convert_order(name, tables, Model)
assert name == self.name
- table, _ = tables[None]
column = self._get_translation_order(tables, Model, name)
- return [Coalesce(NullIf(column, ''), self.sql_column(table))]
+ return [
+ Coalesce(NullIf(column, ''), self.sql_column(tables, Model))]
def definition(self, model, language):
definition = super().definition(model, language)
diff -r 0359c8ecc314 -r 26aca1c56728 trytond/trytond/model/fields/many2many.py
--- a/trytond/trytond/model/fields/many2many.py Tue Feb 10 19:30:10 2026 +0100
+++ b/trytond/trytond/model/fields/many2many.py Thu Jan 29 12:42:56 2026 +0100
@@ -384,14 +384,19 @@
else:
relation = Relation.__table__()
history_where = None
+ relation_tables = {
+ None: (relation, None),
+ }
origin_field = Relation._fields[self.origin]
- origin = getattr(Relation, self.origin).sql_column(relation)
+ origin = getattr(Relation, self.origin).sql_column(
+ relation_tables, Relation)
origin_where = None
if origin_field._type == 'reference':
origin_where = origin.like(Model.__name__ + ',%')
origin = origin_field.sql_id(origin, Relation)
- target = getattr(Relation, self.target).sql_column(relation)
+ target = getattr(Relation, self.target).sql_column(
+ relation_tables, Relation)
if '.' not in name:
if operator.endswith('child_of') or operator.endswith('parent_of'):
if Target != Model:
@@ -481,9 +486,6 @@
relation_domain,
(self.target, 'where', self.filter),
]
- relation_tables = {
- None: (relation, None),
- }
tables, expression = Relation.search_domain(
relation_domain, tables=relation_tables)
query_table = convert_from(None, relation_tables)
diff -r 0359c8ecc314 -r 26aca1c56728 trytond/trytond/model/fields/many2one.py
--- a/trytond/trytond/model/fields/many2one.py Tue Feb 10 19:30:10 2026 +0100
+++ b/trytond/trytond/model/fields/many2one.py Thu Jan 29 12:42:56 2026 +0100
@@ -133,7 +133,7 @@
name, operator, ids = domain
red_sql = reduce_ids(table.id, (i for i in ids if i is not None))
Target = self.get_target()
- path_column = getattr(Target, self.path).sql_column(table)
+ path_column = getattr(Target, self.path).sql_column(tables, Target)
path_column = Coalesce(path_column, '')
cursor.execute(*table.select(
path_column, where=red_sql,
@@ -165,8 +165,8 @@
name, operator, ids = domain
red_sql = reduce_ids(table.id, (i for i in ids if i is not None))
Target = self.get_target()
- left = getattr(Target, self.left).sql_column(table)
- right = getattr(Target, self.right).sql_column(table)
+ left = getattr(Target, self.left).sql_column(tables, Target)
+ right = getattr(Target, self.right).sql_column(tables, Target)
cursor.execute(*table.select(
left, right, where=red_sql,
order_by=[(right - left).asc, left.asc]))
@@ -228,7 +228,7 @@
table, _ = tables[None]
name, operator, value = domain[:3]
- column = self.sql_column(table)
+ column = self.sql_column(tables, Model)
if '.' not in name:
if operator.endswith('child_of') or operator.endswith('parent_of'):
if Target != Model:
@@ -307,7 +307,7 @@
expression = column.in_(query)
else:
target_domain = [target_domain, rule_domain]
- target_tables = self._get_target_tables(tables)
+ target_tables = self._get_target_tables(tables, Model)
target_table, _ = target_tables[None]
_, expression = Target.search_domain(
target_domain, tables=target_tables)
@@ -338,13 +338,13 @@
table, _ = tables[None]
if oname == 'id':
- return [self.sql_column(table)]
+ return [self.sql_column(tables, Model)]
ofield = Target._fields[oname]
- target_tables = self._get_target_tables(tables)
+ target_tables = self._get_target_tables(tables, Model)
return ofield.convert_order(oexpr, target_tables, Target)
- def _get_target_tables(self, tables):
+ def _get_target_tables(self, tables, Model):
Target = self.get_target()
table, _ = tables[None]
target_tables = tables.get(self.name)
@@ -364,7 +364,7 @@
else:
target = Target.__table__()
history_condition = None
- condition = target.id == self.sql_column(table)
+ condition = target.id == self.sql_column(tables, Model)
if history_condition:
condition &= history_condition
target_tables = {
diff -r 0359c8ecc314 -r 26aca1c56728
trytond/trytond/model/fields/multiselection.py
--- a/trytond/trytond/model/fields/multiselection.py Tue Feb 10 19:30:10
2026 +0100
+++ b/trytond/trytond/model/fields/multiselection.py Thu Jan 29 12:42:56
2026 +0100
@@ -90,8 +90,7 @@
if operator not in {'in', 'not in'}:
return super().convert_domain(domain, tables, Model)
database = Transaction().database
- table, _ = tables[None]
- raw_column = self.sql_column(table)
+ raw_column = self.sql_column(tables, Model)
if value is None:
expression = Literal(False)
elif isinstance(value, str):
diff -r 0359c8ecc314 -r 26aca1c56728 trytond/trytond/model/fields/one2many.py
--- a/trytond/trytond/model/fields/one2many.py Tue Feb 10 19:30:10 2026 +0100
+++ b/trytond/trytond/model/fields/one2many.py Thu Jan 29 12:42:56 2026 +0100
@@ -338,8 +338,11 @@
else:
target = Target.__table__()
history_where = None
+ target_tables = {
+ None: (target, None),
+ }
origin_field = Target._fields[self.field]
- origin = getattr(Target, self.field).sql_column(target)
+ origin = getattr(Target, self.field).sql_column(target_tables, Target)
origin_where = None
if origin_field._type == 'reference':
origin_where = origin.like(Model.__name__ + ',%')
@@ -408,9 +411,6 @@
target_domain = [target_domain, rule_domain]
if self.filter:
target_domain = [target_domain, self.filter]
- target_tables = {
- None: (target, None),
- }
tables, expression = Target.search_domain(
target_domain, tables=target_tables)
query_table = convert_from(None, target_tables)
diff -r 0359c8ecc314 -r 26aca1c56728 trytond/trytond/model/fields/reference.py
--- a/trytond/trytond/model/fields/reference.py Tue Feb 10 19:30:10 2026 +0100
+++ b/trytond/trytond/model/fields/reference.py Thu Jan 29 12:42:56 2026 +0100
@@ -204,10 +204,9 @@
pool = Pool()
name, operator, value, target = domain[:4]
Target = pool.get(target)
- table, _ = tables[None]
name, target_name = name.split('.', 1)
assert name == self.name
- column = self.sql_column(table)
+ column = self.sql_column(tables, Model)
target_domain = [(target_name,) + tuple(domain[1:3])
+ tuple(domain[4:])]
if 'active' in Target._fields:
diff -r 0359c8ecc314 -r 26aca1c56728 trytond/trytond/model/fields/selection.py
--- a/trytond/trytond/model/fields/selection.py Tue Feb 10 19:30:10 2026 +0100
+++ b/trytond/trytond/model/fields/selection.py Thu Jan 29 12:42:56 2026 +0100
@@ -146,14 +146,13 @@
@order_method
def convert_order(self, name, tables, Model):
- table, _ = tables[None]
selections = Model.fields_get([name])[name]['selection']
if not isinstance(selections, (tuple, list)):
if not is_instance_method(Model, selections):
selections = getattr(Model, selections)()
else:
selections = []
- column = self.sql_column(table)
+ column = self.sql_column(tables, Model)
if not self.sort:
else_ = len(selections) + 1
selections = ((k, i) for i, (k, v) in enumerate(selections))
diff -r 0359c8ecc314 -r 26aca1c56728 trytond/trytond/model/fields/text.py
--- a/trytond/trytond/model/fields/text.py Tue Feb 10 19:30:10 2026 +0100
+++ b/trytond/trytond/model/fields/text.py Thu Jan 29 12:42:56 2026 +0100
@@ -54,7 +54,7 @@
table, _ = tables[None]
name, operator, value = domain
assert name == self.name
- column = self.sql_column(table)
+ column = self.sql_column(tables, Model)
column = self._domain_column(operator, column)
if operator.endswith('like'):
if database.has_search_full_text():
@@ -81,8 +81,7 @@
@order_method
def convert_order(self, name, tables, Model):
- table, _ = tables[None]
- column = self.sql_column(table)
+ column = self.sql_column(tables, Model)
column = self._domain_column('ilike', column)
column = self._rank_column(column, name, Model)
if column:
diff -r 0359c8ecc314 -r 26aca1c56728 trytond/trytond/model/modelsql.py
--- a/trytond/trytond/model/modelsql.py Tue Feb 10 19:30:10 2026 +0100
+++ b/trytond/trytond/model/modelsql.py Thu Jan 29 12:42:56 2026 +0100
@@ -1192,6 +1192,7 @@
history_clause = (column <= Transaction().context['_datetime'])
history_order = (column.desc, Column(table, '__id').desc)
history_limit = 1
+ tables = {None: (table, None)}
columns = {}
for f in all_fields:
@@ -1200,7 +1201,7 @@
if f in _TABLE_QUERY_COLUMNS and cls._is_table_query():
column = _TABLE_QUERY_COLUMNS[f]
else:
- column = field.sql_column(table)
+ column = field.sql_column(tables, cls)
columns[f] = column.as_(f)
if backend.name == 'sqlite':
columns[f].output_name += ' [%s]' % field.sql_type().base
@@ -1241,7 +1242,6 @@
if 'id' not in fields_names:
columns['id'] = table.id.as_('id')
- tables = {None: (table, None)}
if domain:
tables, dom_exp = cls.search_domain(
domain, active_test=False, tables=tables)
@@ -1581,10 +1581,9 @@
tree_ids = {}
for fname in cls._mptt_fields:
- field = cls._fields[fname]
tree_ids[fname] = []
for sub_ids in grouped_slice(ids):
- where = reduce_ids(field.sql_column(table), sub_ids)
+ where = reduce_ids(Column(table, fname), sub_ids)
cursor.execute(*table.select(table.id, where=where))
tree_ids[fname] += [x[0] for x in cursor]
@@ -1841,9 +1840,8 @@
rule_domain, active_test=False, tables=tables)
expression &= domain_exp
main_table, _ = tables[None]
- table = convert_from(None, tables)
columns = cls.__searched_columns(
- main_table, eager=not count and not query)
+ tables, eager=not count and not query)
o_idx = 0
for oexpr, otype in order:
@@ -1858,6 +1856,7 @@
orderings.extend([otype] * len(forder))
done_orderings = True
+ table = convert_from(None, tables)
union_tables.append(table.select(
*columns, where=expression))
expression = None
@@ -1874,7 +1873,8 @@
return tables, expression, orderings
@classmethod
- def __searched_columns(cls, table, *, eager=False, history=False):
+ def __searched_columns(cls, tables, *, eager=False, history=False):
+ table, _ = tables[None]
columns = [table.id.as_('id')]
if (cls._history and Transaction().context.get('_datetime')
and (eager or history)):
@@ -1884,7 +1884,7 @@
if eager:
table_query = cls._is_table_query()
- columns += [f.sql_column(table).as_(n)
+ columns += [f.sql_column(tables, cls).as_(n)
for n, f in sorted(cls._fields.items())
if not hasattr(f, 'get')
and n != 'id'
@@ -1955,16 +1955,20 @@
order_by = cls.__search_order(order, tables)
# compute it here because __search_order might modify tables
- table = convert_from(None, tables)
if query:
columns = [main_table.id.as_('id')]
else:
- columns = cls.__searched_columns(main_table, eager=True)
+ columns = cls.__searched_columns(tables, eager=True)
+ if union_orderings:
+ columns = [
+ Column(main_table, c.output_name).as_(c.output_name)
+ for c in columns]
if backend.name == 'sqlite':
for column in columns:
field = cls._fields.get(column.output_name)
if field:
column.output_name += ' [%s]' % field.sql_type().base
+ table = convert_from(None, tables)
select = table.select(
*columns, where=expression, limit=limit, offset=offset,
order_by=order_by)