[FIX] fields: make related_sudo work for draft records (2)
Traversing new records in a different cache requires that all new records on the path are copied across caches. Make the copy across caches recursive when the first record on the path is a new record.
This commit is contained in:
@@ -393,28 +393,46 @@ class TestNewFields(common.TransactionCase):
|
||||
|
||||
@mute_logger('openerp.addons.base.ir.ir_model')
|
||||
def test_41_new_related(self):
|
||||
""" test the behavior of related fields on new records. """
|
||||
discussion = self.env.ref('test_new_api.discussion_0')
|
||||
access = self.env.ref('test_new_api.access_discussion')
|
||||
|
||||
""" test the behavior of related fields starting on new records. """
|
||||
# make discussions unreadable for demo user
|
||||
access = self.env.ref('test_new_api.access_discussion')
|
||||
access.write({'perm_read': False})
|
||||
|
||||
# create an environment for demo user
|
||||
demo_env = self.env(user=self.env.ref('base.user_demo'))
|
||||
self.assertEqual(demo_env.user.login, "demo")
|
||||
env = self.env(user=self.env.ref('base.user_demo'))
|
||||
self.assertEqual(env.user.login, "demo")
|
||||
|
||||
# create a new message as demo user
|
||||
values = {'discussion': discussion.id}
|
||||
message = demo_env['test_new_api.message'].new(values)
|
||||
discussion = self.env.ref('test_new_api.discussion_0')
|
||||
message = env['test_new_api.message'].new({'discussion': discussion})
|
||||
self.assertEqual(message.discussion, discussion)
|
||||
|
||||
# read the related field discussion_name
|
||||
self.assertEqual(message.discussion.env, demo_env)
|
||||
self.assertEqual(message.discussion.env, env)
|
||||
self.assertEqual(message.discussion_name, discussion.name)
|
||||
with self.assertRaises(AccessError):
|
||||
message.discussion.name
|
||||
|
||||
@mute_logger('openerp.addons.base.ir.ir_model')
|
||||
def test_42_new_related(self):
|
||||
""" test the behavior of related fields traversing new records. """
|
||||
# make discussions unreadable for demo user
|
||||
access = self.env.ref('test_new_api.access_discussion')
|
||||
access.write({'perm_read': False})
|
||||
|
||||
# create an environment for demo user
|
||||
env = self.env(user=self.env.ref('base.user_demo'))
|
||||
self.assertEqual(env.user.login, "demo")
|
||||
|
||||
# create a new discussion and a new message as demo user
|
||||
discussion = env['test_new_api.discussion'].new({'name': 'Stuff'})
|
||||
message = env['test_new_api.message'].new({'discussion': discussion})
|
||||
self.assertEqual(message.discussion, discussion)
|
||||
|
||||
# read the related field discussion_name
|
||||
self.assertNotEqual(message.sudo().env, message.env)
|
||||
self.assertEqual(message.discussion_name, discussion.name)
|
||||
|
||||
def test_50_defaults(self):
|
||||
""" test default values. """
|
||||
fields = ['discussion', 'body', 'author', 'size']
|
||||
|
||||
+11
-3
@@ -58,6 +58,15 @@ def _check_value(value):
|
||||
""" Return ``value``, or call its getter if ``value`` is a :class:`SpecialValue`. """
|
||||
return value.get() if isinstance(value, SpecialValue) else value
|
||||
|
||||
def copy_cache(records, env):
|
||||
""" Recursively copy the cache of ``records`` to the environment ``env``. """
|
||||
for record, target in zip(records, records.with_env(env)):
|
||||
if not target._cache:
|
||||
for name, value in record._cache.iteritems():
|
||||
target[name] = value
|
||||
if isinstance(value, BaseModel):
|
||||
copy_cache(value, env)
|
||||
|
||||
|
||||
def resolve_all_mro(cls, name, reverse=False):
|
||||
""" Return the (successively overridden) values of attribute ``name`` in ``cls``
|
||||
@@ -538,10 +547,9 @@ class Field(object):
|
||||
# when related_sudo, bypass access rights checks when reading values
|
||||
others = records.sudo() if self.related_sudo else records
|
||||
for record, other in zip(records, others):
|
||||
if not record.id:
|
||||
if not record.id and record.env != other.env:
|
||||
# draft records: copy record's cache to other's cache first
|
||||
for name, value in record._cache.iteritems():
|
||||
other[name] = value
|
||||
copy_cache(record, other.env)
|
||||
# traverse the intermediate fields; follow the first record at each step
|
||||
for name in self.related[:-1]:
|
||||
other = other[name][:1]
|
||||
|
||||
Reference in New Issue
Block a user