Use dualmethod on ModelStorage.save
issue4197 review8671002
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user