diff --git a/CHANGELOG b/CHANGELOG
index 44092915c0..82992ac1bd 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,6 @@
+* Allow empty order clause
+* Change editable tree attribute into boolean
+* Send default order to clients
* Replace advisory lock by SKIP LOCKED in queue pulling
* Load WSGI middleware from configuration
* Add help text to Dict keys
diff --git a/doc/ref/models/models.rst b/doc/ref/models/models.rst
index d06740ce30..fae92da415 100644
--- a/doc/ref/models/models.rst
+++ b/doc/ref/models/models.rst
@@ -443,10 +443,10 @@ Class methods:
[ ('field name', 'ASC'), ('other field name', 'DESC'), ... ]
The first element of the tuple is a field name of the model and the second
- is the sort ordering as `ASC` for ascending or `DESC` for descending. This
- second element may contain 'NULLS FIRST' or 'NULLS LAST' to sort null
- values before or after non-null values. If neither is specified the default
- behavior of the backend is used.
+ is the sort ordering as `ASC` for ascending, `DESC` for descending or empty
+ for a default order. This second element may contain 'NULLS FIRST' or
+ 'NULLS LAST' to sort null values before or after non-null values. If
+ neither is specified the default behavior of the backend is used.
In case the field used is a :class:`fields.Many2One`, it is also possible
to use the dotted notation to sort on a specific field from the target
diff --git a/doc/topics/views/index.rst b/doc/topics/views/index.rst
index cb04df8d82..9fb40e14c2 100644
--- a/doc/topics/views/index.rst
+++ b/doc/topics/views/index.rst
@@ -519,9 +519,7 @@ Each tree view must start with this tag.
* ``on_write``: see form-attributes-on_write_.
- * ``editable``: If it is set to ``top`` or ``bottom``, the list becomes
- editable and the new record will be added on ``top`` or ``bottom`` of the
- list.
+ * ``editable``: A boolean to specify if the list is editable.
* ``sequence``: The name of the field that is used for sorting. This field
must be an integer and it will be updated to match the new sort order
diff --git a/trytond/ir/action.py b/trytond/ir/action.py
index c9ca2ebcba..ca7b1dc1ec 100644
--- a/trytond/ir/action.py
+++ b/trytond/ir/action.py
@@ -10,6 +10,7 @@ from sql import Null
from trytond.config import config
from trytond.i18n import gettext
from trytond.model.exceptions import ValidationError
+from trytond.pyson import PYSONEncoder
from ..model import (
ModelView, ModelStorage, ModelSQL, DeactivableMixin, fields,
sequence_ordered)
@@ -880,6 +881,8 @@ class ActionActWindow(ActionMixin, ModelSQL, ModelView):
@classmethod
def get_pyson(cls, windows, name):
+ pool = Pool()
+ encoder = PYSONEncoder()
pysons = {}
field = name[6:]
defaults = {
@@ -888,6 +891,12 @@ class ActionActWindow(ActionMixin, ModelSQL, ModelView):
'search_value': '[]',
}
for window in windows:
+ if not window.order and field == 'order':
+ if window.res_model:
+ defaults['order'] = encoder.encode(
+ getattr(pool.get(window.res_model), '_order', 'null'))
+ else:
+ defaults['order'] = 'null'
pysons[window.id] = (getattr(window, field)
or defaults.get(field, 'null'))
return pysons
diff --git a/trytond/ir/attachment.py b/trytond/ir/attachment.py
index c9f92a100c..5aa85afdf6 100644
--- a/trytond/ir/attachment.py
+++ b/trytond/ir/attachment.py
@@ -54,7 +54,10 @@ class Attachment(ResourceMixin, ModelSQL, ModelView):
@classmethod
def __setup__(cls):
super().__setup__()
- cls._order.insert(0, ('create_date', 'DESC'))
+ cls._order = [
+ ('create_date', 'DESC'),
+ ('id', 'DESC'),
+ ]
@classmethod
def __register__(cls, module_name):
diff --git a/trytond/ir/ui/tree.rnc b/trytond/ir/ui/tree.rnc
index b694f5f4cd..ba8c4f7134 100644
--- a/trytond/ir/ui/tree.rnc
+++ b/trytond/ir/ui/tree.rnc
@@ -5,7 +5,7 @@ tree = element tree { attlist.tree,
| button)*
}
attlist.tree &= attribute on_write { text }?
-attlist.tree &= attribute editable { "top" | "bottom" }?
+attlist.tree &= attribute editable { "0" | "1" }?
attlist.tree &= attribute sequence { text }?
attlist.tree &=
[ a:defaultValue = "0" ] attribute keyword_open { "0" | "1" }?
diff --git a/trytond/ir/ui/tree.rng b/trytond/ir/ui/tree.rng
index 0c5651fc08..5938647a92 100644
--- a/trytond/ir/ui/tree.rng
+++ b/trytond/ir/ui/tree.rng
@@ -27,8 +27,8 @@
editable
- top
- bottom
+ 0
+ 1
diff --git a/trytond/ir/view/attachment_list.xml b/trytond/ir/view/attachment_list.xml
index 4759271b97..cf5b577b80 100644
--- a/trytond/ir/view/attachment_list.xml
+++ b/trytond/ir/view/attachment_list.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/trytond/ir/view/lang_list.xml b/trytond/ir/view/lang_list.xml
index b50df81d07..2d06b1d064 100644
--- a/trytond/ir/view/lang_list.xml
+++ b/trytond/ir/view/lang_list.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/trytond/ir/view/module_config_wizard_item_list.xml b/trytond/ir/view/module_config_wizard_item_list.xml
index 51bfa46f7f..874988591c 100644
--- a/trytond/ir/view/module_config_wizard_item_list.xml
+++ b/trytond/ir/view/module_config_wizard_item_list.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/trytond/ir/view/translation_list.xml b/trytond/ir/view/translation_list.xml
index 9b5df31a33..0bbe31da57 100644
--- a/trytond/ir/view/translation_list.xml
+++ b/trytond/ir/view/translation_list.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/trytond/model/fields/many2many.py b/trytond/model/fields/many2many.py
index 0c68be0d4a..0191cc2175 100644
--- a/trytond/model/fields/many2many.py
+++ b/trytond/model/fields/many2many.py
@@ -455,6 +455,9 @@ class Many2Many(Field):
definition['search_context'] = encoder.encode(self.search_context)
definition['search_order'] = encoder.encode(self.search_order)
definition['sortable'] &= hasattr(model, 'order_' + self.name)
+ definition['order'] = encoder.encode(
+ getattr(model, '_order', None)
+ if self.order is None else self.order)
if self.size is not None:
definition['size'] = encoder.encode(self.size)
return definition
diff --git a/trytond/model/fields/one2many.py b/trytond/model/fields/one2many.py
index 660c391547..ff64418c84 100644
--- a/trytond/model/fields/one2many.py
+++ b/trytond/model/fields/one2many.py
@@ -352,4 +352,7 @@ class One2Many(Field):
if self.size is not None:
definition['size'] = encoder.encode(self.size)
definition['sortable'] &= hasattr(model, 'order_' + self.name)
+ definition['order'] = encoder.encode(
+ getattr(model, '_order', None)
+ if self.order is None else self.order)
return definition
diff --git a/trytond/model/modelsql.py b/trytond/model/modelsql.py
index 13c0c41e77..13428154cb 100644
--- a/trytond/model/modelsql.py
+++ b/trytond/model/modelsql.py
@@ -188,7 +188,7 @@ class ModelSQL(ModelStorage):
cls._sql_constraints.append(
('id_positive', Check(table, table.id >= 0),
'ir.msg_id_positive'))
- cls._order = [('id', 'ASC')]
+ cls._order = [('id', None)]
if issubclass(cls, ModelView):
cls.__rpc__.update({
'history_revisions': RPC(),
@@ -1256,11 +1256,14 @@ class ModelSQL(ModelStorage):
for oexpr, otype in order:
fname, _, extra_expr = oexpr.partition('.')
field = cls._fields[fname]
- otype = otype.upper()
- try:
- otype, null_ordering = otype.split(' ', 1)
- except ValueError:
- null_ordering = None
+ if not otype:
+ otype, null_ordering = 'ASC', None
+ else:
+ otype = otype.upper()
+ try:
+ otype, null_ordering = otype.split(' ', 1)
+ except ValueError:
+ null_ordering = None
Order = order_types[otype]
NullOrdering = null_ordering_types[null_ordering]
forder = field.convert_order(oexpr, tables, cls)