[IMP] conversion back from m2o t-field to openerp value

Instead of doing a name_get on the edited value and trying to find out
an m2o to assign back (which there's pretty much no chance of given
there's no autocompletion or anything), alter the m2o record in-place
by setting the provided edited value to its _rec_name.

Ideally, both features could be supported via more advanced m2o
edition widgets which would allow selecting an existing m2o, creating
a new m2o record from scratch or (maybe) editing the existing m2o's
display_name if possible, somewhat similar to what the form view
provides.

Without these though, the only action which makes any sense is to edit
the user-visible "value" where it is found, as with more normal
fields.

bzr revid: xmo@openerp.com-20131218140917-4eo2o55yfcumzhov
This commit is contained in:
Xavier Morel 2013-12-18 15:09:17 +01:00
parent eb44a6b21e
commit e04983ae69
3 changed files with 75 additions and 26 deletions

View File

@ -204,12 +204,29 @@ class ManyToOne(orm.AbstractModel):
_inherit = ['website.qweb.field', 'ir.qweb.field.many2one']
def from_html(self, cr, uid, model, column, element, context=None):
# FIXME: this behavior is really weird, what if the user wanted to edit the name of the related thingy? Should m2os really be editable without a widget?
matches = self.pool[column._obj].name_search(
cr, uid, name=element.text_content().strip(), context=context)
# FIXME: no match? More than 1 match?
assert len(matches) == 1
return matches[0][0]
# FIXME: layering violations all the things
Model = self.pool[element.get('data-oe-model')]
M2O = self.pool[column._obj]
field = element.get('data-oe-field')
id = int(element.get('data-oe-id'))
value = element.text_content().strip()
# if anything blows up, just ignore it and bail
try:
# get parent record
[obj] = Model.read(cr, uid, [id], [field])
# get m2o record id
(m2o_id, _) = obj[field]
# assume _rec_name and write directly to it
M2O.write(cr, uid, [m2o_id], {
M2O._rec_name: value
}, context=context)
except:
logger.exception("Could not save %r to m2o field %s of model %s",
value, field, Model._name)
# not necessary, but might as well be explicit about it
return None
class HTML(orm.AbstractModel):
_name = 'website.qweb.field.html'
@ -281,7 +298,7 @@ class Image(orm.AbstractModel):
match.group('module'), 'static', *(rest.split('/')))
if not path:
return False
return None
try:
with open(path, 'rb') as f:
@ -292,7 +309,7 @@ class Image(orm.AbstractModel):
return f.read().encode('base64')
except Exception:
logger.exception("Failed to load local image %r", url)
return False
return None
def load_remote_url(self, url):
try:
@ -310,7 +327,7 @@ class Image(orm.AbstractModel):
image.load()
except Exception:
logger.exception("Failed to load remote image %r", url)
return False
return None
# don't use original data in case weird stuff was smuggled in, with
# luck PIL will remove some of it?

View File

@ -70,9 +70,11 @@ class view(osv.osv):
el.get('data-oe-type'))
value = converter.from_html(cr, uid, Model, column, el)
Model.write(cr, uid, [int(el.get('data-oe-id'))], {
field: value
}, context=context)
if value is not None:
# TODO: batch writes?
Model.write(cr, uid, [int(el.get('data-oe-id'))], {
field: value
}, context=context)
def to_field_ref(self, cr, uid, el, context=None):
# filter out meta-information inserted in the document

View File

@ -63,20 +63,6 @@ class TestConvertBack(common.TransactionCase):
self.field_roundtrip('char', "ⒸⓄⓇⒼⒺ")
def test_m2o(self):
Sub = self.registry('website.converter.test.sub')
sub = partial(Sub.create, self.cr, self.uid)
ids = [
sub({'name': "Foo"}),
sub({'name': "Bar"}),
sub({'name': "Baz"}),
]
self.field_rountrip_result(
'many2one',
ids[2],
ids[2])
def test_selection(self):
self.field_roundtrip('selection', 3)
@ -104,3 +90,47 @@ class TestConvertBack(common.TransactionCase):
You never know
You never know until you go
""")
def test_m2o(self):
""" the M2O field conversion (from html) is markedly different from
others as it directly writes into the m2o and returns nothing at all.
"""
model = 'website.converter.test'
field = 'many2one'
Sub = self.registry('website.converter.test.sub')
sub_id = Sub.create(self.cr, self.uid, {'name': "Foo"})
Model = self.registry(model)
id = Model.create(self.cr, self.uid, {field: sub_id})
[record] = Model.browse(self.cr, self.uid, [id])
e = document.createElement('span')
field_value = 'record.%s' % field
e.setAttribute('t-field', field_value)
rendered = self.registry('website.qweb').render_tag_field(
e, {'field': field_value}, '', ir_qweb.QWebContext(self.cr, self.uid, {
'record': record,
}))
element = html.fromstring(rendered, parser=html.HTMLParser(encoding='utf-8'))
# emulate edition
element.text = "New content"
column = Model._all_columns[field].column
converter = self.registry('website.qweb').get_converter_for(
element.get('data-oe-type'))
value_back = converter.from_html(
self.cr, self.uid, model, column, element)
self.assertIsNone(
value_back, "the m2o converter should return None to avoid spurious"
" or useless writes on the parent record")
self.assertEqual(
Sub.browse(self.cr, self.uid, sub_id).name,
"New content",
"element edition should have been written directly to the m2o record"
)