diff --git a/unserialize_field/__openerp__.py b/unserialize_field/__openerp__.py
index 8d6d30be0..b639ce348 100644
--- a/unserialize_field/__openerp__.py
+++ b/unserialize_field/__openerp__.py
@@ -23,13 +23,23 @@
{
'name': 'Make database fields from fields that live in serialized fields',
'version': '1.0',
- 'description': """To be able to search for fields with standard methods,
-they have to be database fields. This addon makes it possible to unserialize
-them afterwards.""",
+ 'description': """
+Sparse, or serialized fields do not live as a column in the database table.
+Instead, their values are stored in JSON arrays in a separate field. As a
+result, these fields cannot be searched or sorted by.
+
+If such a sparse field is created as 'manual', this module can unserialize
+the field. Its field definition and values will then be migrated to a
+proper database column. A real life use case where you encounter many
+of such fields is the Magento-OpenERP connector.
+
+For technical reasons, many2many and one2many fields are not supported.
+""",
'author': 'Therp BV',
'website': 'http://www.therp.nl',
+ 'version': '1.0',
"category": "Tools",
- "depends": [],
+ "depends": ['base'],
"data": ['ir_model_fields.xml'],
'installable': True,
'active': False,
diff --git a/unserialize_field/ir_model_fields.py b/unserialize_field/ir_model_fields.py
index ea5d25cf4..c5b5699f3 100644
--- a/unserialize_field/ir_model_fields.py
+++ b/unserialize_field/ir_model_fields.py
@@ -19,91 +19,97 @@
# along with this program. If not, see .
#
##############################################################################
-from openerp.osv.orm import Model
-from openerp.osv import fields
+from openerp.osv import orm
+from openerp.tools.translate import _
-class ir_model_fields(Model):
+class ir_model_fields(orm.Model):
_inherit = 'ir.model.fields'
def action_unserialize_field(self, cr, uid, ids, context=None):
step = 1000
offset = 0
- for this in self.browse(cr, uid, ids, context=context):
- pool_obj = self.pool.get(this.model_id.model)
- needs_write = self.create_database_column(
- cr, uid, pool_obj, this.name)
- while needs_write:
- ids = pool_obj.search(
+ # Prevent _auto_init to commit the transaction
+ # before the data is migrated safely
+ commit_org = cr.commit
+ cr.commit = lambda *args: None
+
+ try:
+ for this in self.browse(cr, uid, ids, context=context):
+ pool_obj = self.pool.get(this.model_id.model)
+ self.create_database_column(cr, uid, pool_obj, this.name,
+ context=context)
+ while True:
+ ids = pool_obj.search(
cr, uid,
[(this.serialization_field_id.name, '!=', '{}')],
offset=offset*step, limit=step, context=context)
- if not ids:
- break
- for data in pool_obj.read(cr, uid, ids,
- [this.serialization_field_id.name],
- context=context):
- self.unserialize_field(cr, uid, pool_obj, data,
- this.serialization_field_id.name,
- this.name, context=context)
- offset += 1
+ if not ids:
+ break
+ for data in pool_obj.read(cr, uid, ids,
+ [this.serialization_field_id.name],
+ context=context):
+ self.unserialize_field(cr, uid, pool_obj, data,
+ this.serialization_field_id.name,
+ this.name, context=context)
+ offset += 1
+ finally:
+ cr.commit = commit_org
+
return True
- def create_database_column(self, cr, uid, pool_obj, field_name):
- needs_write = True
+ def create_database_column(self, cr, uid, pool_obj, field_name,
+ context=None):
old = pool_obj._columns[field_name]
- field_declaration_args = []
- field_declaration_kwargs = dict(
- manual=old.manual,
- string=old.string,
- required=old.required,
- readonly=old.readonly,
- domain=old._domain,
- context=old._context,
- states=old.states,
- priority=old.priority,
- change_default=old.change_default,
- size=old.size,
- ondelete=old.ondelete,
- translate=old.translate,
- select=old.select,
- )
-
- if old._type == 'many2one':
- field_declaration_args = [old._obj]
- elif old._type == 'selection':
- field_declaration_args = [old.selection]
- elif old._type == 'one2many':
- field_declaration_args = [old._obj, old._fields_id]
- field_declaration_kwargs['limit'] = old._limit
- needs_write = False
- elif old._type == 'many2many':
- field_declaration_args = [old._obj]
- field_declaration_kwargs['rel'] = old._rel
- field_declaration_kwargs['id1'] = old._id1
- field_declaration_kwargs['id2'] = old._id2
- field_declaration_kwargs['limit'] = old._limit
- needs_write = False
-
- field_declaration = getattr(fields, old._type)(
- *field_declaration_args,
- **field_declaration_kwargs)
+ if not old.manual:
+ raise orm.except_orm(
+ _('Error'),
+ _('This operation can only be performed on manual fields'))
+ if old._type == 'many2many':
+ # Cross table name length of manually created many2many
+ # fields can easily become too large. Although it would
+ # probably work if the table name length was within bounds,
+ # this scenario has not been tested because of this limitation.
+ raise orm.except_orm(
+ _("Error"),
+ _("Many2many fields are not supported. See "
+ "https://bugs.launchpad.net/openobject-server/+bug/1174078 "
+ "for more information"))
+ if old._type == 'one2many':
+ # How to get a safe field name for the relation field
+ # on the target model?
+ raise orm.except_orm(
+ _("Error"),
+ _("One2many fields are not handled yet"))
+
+ # ORM prohibits to change the 'storing system' of the field
+ cr.execute("""
+ UPDATE ir_model_fields
+ SET serialization_field_id = NULL
+ WHERE name = %s and model = %s
+ """, (field_name, pool_obj._name))
- pool_obj._columns[field_name] = field_declaration
+ del pool_obj._columns[field_name]
+ pool_obj.__init__(self.pool, cr)
pool_obj._auto_init(cr, {'update_custom_fields': True})
- return needs_write
def unserialize_field(self, cr, uid, pool_obj, read_record,
serialization_field_name, field_name,
context=None):
- if not field_name in read_record[serialization_field_name]:
+ serialized_values = read_record[serialization_field_name]
+ if not field_name in serialized_values:
return False
- pool_obj.write(
+
+ value = serialized_values.pop(field_name)
+ if pool_obj._columns[field_name]._type in ('many2many', 'one2many'):
+ value = [(6, 0, value)]
+
+ return pool_obj.write(
cr, uid, read_record['id'],
{
- field_name:
- read_record[serialization_field_name][field_name],
+ field_name: value,
+ serialization_field_name: serialized_values,
},
context=context)
- return True
+
diff --git a/unserialize_field/ir_model_fields.xml b/unserialize_field/ir_model_fields.xml
index 17f6701bb..4a92c4d39 100644
--- a/unserialize_field/ir_model_fields.xml
+++ b/unserialize_field/ir_model_fields.xml
@@ -16,5 +16,21 @@
+
+
+ form
+ ir.model
+
+
+
+
+
+
+
+
+