Use dualmethod on ModelStorage.save

issue4197
review8671002
This commit is contained in:
Cédric Krier
2014-11-01 11:52:55 +01:00
parent ab3a4692ee
commit b13abebc81
8 changed files with 107 additions and 46 deletions
+1
View File
@@ -1,3 +1,4 @@
* Use dualmethod on ModelStorage.save
* New API for on_change: instance changes
* Add restore_history_before on ModelSQL
* Remove img_{width,height} form attributes
+7 -5
View File
@@ -230,7 +230,7 @@ Static methods:
Return the default value for :attr:`create_date`.
CLass methods:
Class methods:
.. classmethod:: ModelStorage.create(vlist)
@@ -336,6 +336,12 @@ CLass methods:
method must be overridden to add validation and must raise an exception if
validation fails.
Dual methods:
.. classmethod:: ModelStorage.save(records)
Save the modification made on the records.
Instance methods:
.. method:: ModelStorage.get_rec_name(name)
@@ -343,10 +349,6 @@ Instance methods:
Getter for the :class:`trytond.model.fields.Function` field
:attr:`rec_name`.
.. method:: ModelStorage.save()
Save the modification made on the record instance.
========
ModelSQL
========
+1 -1
View File
@@ -1,6 +1,6 @@
#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 ..model import ModelView, ModelSQL, fields
from ..model import ModelView, ModelSQL, fields, dualmethod
from ..tools import safe_eval
from ..transaction import Transaction
from ..cache import Cache
+7 -18
View File
@@ -780,7 +780,7 @@ class Translation(ModelSQL, ModelView):
(model_data.db_id, model_data.noupdate)
translations = set()
to_create = []
to_save = []
pofile = polib.pofile(po_path)
id2translation = {}
@@ -872,26 +872,15 @@ class Translation(ModelSQL, ModelView):
continue
if not ids:
to_create.append(translation._save_values)
else:
to_write = []
to_save.append(translation)
elif not noupdate:
for translation_id in ids:
old_translation = id2translation[translation_id]
if (old_translation.value != translation.value
or old_translation.fuzzy !=
translation.fuzzy):
to_write.append(old_translation)
with Transaction().set_context(module=module):
if to_write and not noupdate:
cls.write(to_write, {
'value': translation.value,
'fuzzy': translation.fuzzy,
})
translations |= set(cls.browse(ids))
old_translation.value = translation.value
old_translation.fuzzy = translation.fuzzy
to_save.append(old_translation)
if to_create:
with Transaction().set_context(module=module):
translations |= set(cls.create(to_create))
translations |= set(cls.save(to_save))
if translations:
all_translations = set(cls.search([
+2 -1
View File
@@ -9,6 +9,7 @@ from .workflow import Workflow
from .dictschema import DictSchemaMixin
from .match import MatchMixin
from .union import UnionMixin
from .descriptors import dualmethod
__all__ = ['Model', 'ModelView', 'ModelStorage', 'ModelSingleton', 'ModelSQL',
'Workflow', 'DictSchemaMixin', 'MatchMixin', 'UnionMixin']
'Workflow', 'DictSchemaMixin', 'MatchMixin', 'UnionMixin', 'dualmethod']
+34
View File
@@ -0,0 +1,34 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import functools
class dualmethod(object):
"""Descriptor implementing combination of class and instance method
When called on an instance, the class is passed as the first argument and a
list with the instance as the second.
When called on a class, the class itsefl is passed as the first argument.
>>> class Example(object):
... @dualmethod
... def method(cls, instances):
... print len(instances)
...
>>> Example.method([Example()])
1
>>> Example().method()
1
"""
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
@functools.wraps(self.func)
def newfunc(*args, **kwargs):
if instance:
return self.func(owner, [instance], *args, **kwargs)
else:
return self.func(owner, *args, **kwargs)
return newfunc
+43 -21
View File
@@ -27,6 +27,7 @@ from trytond.cache import LRUDict, freeze
from trytond import backend
from trytond.rpc import RPC
from .modelview import ModelView
from .descriptors import dualmethod
__all__ = ['ModelStorage']
@@ -1391,27 +1392,48 @@ class ModelStorage(Model):
values[fname] = value
return values
def save(self):
save_values = self._save_values
values = self._values
self._values = None
if save_values or self.id < 0:
try:
with Transaction().set_cursor(self._cursor), \
Transaction().set_user(self._user), \
Transaction().set_context(self._context):
if self.id < 0:
self._ids.remove(self.id)
try:
self.id = self.create([save_values])[0].id
finally:
self._ids.append(self.id)
else:
self.write([self], save_values)
except:
self._values = values
raise
self._init_values = None
@dualmethod
def save(cls, records):
if not records:
return
values = {}
save_values = {}
to_create = []
to_write = []
cursor = records[0]._cursor
user = records[0]._user
context = records[0]._context
for record in records:
assert cursor == record._cursor
assert user == record._user
assert context == record._context
save_values[record] = record._save_values
values[record] = record._values
record._values = None
if record.id is None or record.id < 0:
to_create.append(record)
elif save_values[record]:
to_write.append(record)
transaction = Transaction()
try:
with transaction.set_cursor(cursor), \
transaction.set_user(user), \
transaction.set_context(context):
if to_create:
news = cls.create([save_values[r] for r in to_create])
for record, new in izip(to_create, news):
record._ids.remove(record.id)
record.id = new.id
record._ids.append(record.id)
if to_write:
cls.write(*sum(
(([r], save_values[r]) for r in to_write), ()))
except:
for record in records:
record._values = values[record]
raise
for record in records:
record._init_values = None
class EvalEnvironment(dict):
+12
View File
@@ -0,0 +1,12 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import unittest
import doctest
from trytond.model import descriptors
def suite():
suite = unittest.TestSuite()
suite.addTest(doctest.DocTestSuite(descriptors))
return suite