[IMP] models: refactor _add_manual_fields to make it extendable
This commit is contained in:
committed by
Géry Debongnie
parent
979c553918
commit
1c4661ee9d
@@ -1,6 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
import datetime
|
||||
import dateutil
|
||||
import logging
|
||||
import time
|
||||
from collections import defaultdict
|
||||
|
||||
from odoo import api, fields, models, SUPERUSER_ID, tools, _
|
||||
@@ -18,6 +21,20 @@ def encode(s):
|
||||
return s.encode('utf8') if isinstance(s, unicode) else s
|
||||
|
||||
|
||||
# base environment for doing a safe_eval
|
||||
SAFE_EVAL_BASE = {
|
||||
'datetime': datetime,
|
||||
'dateutil': dateutil,
|
||||
'time': time,
|
||||
}
|
||||
|
||||
def make_compute(text, deps):
|
||||
""" Return a compute function from its code body and dependencies. """
|
||||
func = lambda self: safe_eval(text, SAFE_EVAL_BASE, {'self': self}, mode="exec")
|
||||
deps = [arg.strip() for arg in (deps or "").split(",")]
|
||||
return api.depends(*deps)(func)
|
||||
|
||||
|
||||
#
|
||||
# IMPORTANT: this must be the first model declared in the module
|
||||
#
|
||||
@@ -557,6 +574,57 @@ class IrModelFields(models.Model):
|
||||
res.append((field.id, '%s (%s)' % (field.field_description, field.model)))
|
||||
return res
|
||||
|
||||
@api.model
|
||||
def _instanciate(self, field_data, partial):
|
||||
""" Return a field instance corresponding to parameters ``field_data``. """
|
||||
attrs = {
|
||||
'manual': True,
|
||||
'string': field_data['field_description'],
|
||||
'help': field_data['help'],
|
||||
'index': bool(field_data['index']),
|
||||
'copy': bool(field_data['copy']),
|
||||
'related': field_data['related'],
|
||||
'required': bool(field_data['required']),
|
||||
'readonly': bool(field_data['readonly']),
|
||||
'store': bool(field_data['store']),
|
||||
}
|
||||
# FIXME: ignore field_data['serialization_field_id']
|
||||
if field_data['ttype'] in ('char', 'text', 'html'):
|
||||
attrs['translate'] = bool(field_data['translate'])
|
||||
attrs['size'] = field_data['size'] or None
|
||||
elif field_data['ttype'] in ('selection', 'reference'):
|
||||
attrs['selection'] = safe_eval(field_data['selection'])
|
||||
elif field_data['ttype'] == 'many2one':
|
||||
if partial and field_data['relation'] not in self.env:
|
||||
return
|
||||
attrs['comodel_name'] = field_data['relation']
|
||||
attrs['ondelete'] = field_data['on_delete']
|
||||
attrs['domain'] = safe_eval(field_data['domain']) if field_data['domain'] else None
|
||||
elif field_data['ttype'] == 'one2many':
|
||||
if partial and not (
|
||||
field_data['relation'] in self.env and (
|
||||
field_data['relation_field'] in self.env[field_data['relation']]._fields or
|
||||
field_data['relation_field'] in self.pool.get_manual_fields(self._cr, field_data['relation'])
|
||||
)):
|
||||
return
|
||||
attrs['comodel_name'] = field_data['relation']
|
||||
attrs['inverse_name'] = field_data['relation_field']
|
||||
attrs['domain'] = safe_eval(field_data['domain']) if field_data['domain'] else None
|
||||
elif field_data['ttype'] == 'many2many':
|
||||
if partial and field_data['relation'] not in self.env:
|
||||
return
|
||||
attrs['comodel_name'] = field_data['relation']
|
||||
rel, col1, col2 = self._custom_many2many_names(field_data['model'], field_data['relation'])
|
||||
attrs['relation'] = field_data['relation_table'] or rel
|
||||
attrs['column1'] = field_data['column1'] or col1
|
||||
attrs['column2'] = field_data['column2'] or col2
|
||||
attrs['domain'] = safe_eval(field_data['domain']) if field_data['domain'] else None
|
||||
# add compute function if given
|
||||
if field_data['compute']:
|
||||
attrs['compute'] = make_compute(field_data['compute'], field_data['depends'])
|
||||
|
||||
return fields.Field.by_type[field_data['ttype']](**attrs)
|
||||
|
||||
|
||||
class IrModelConstraint(models.Model):
|
||||
"""
|
||||
|
||||
+6
-65
@@ -29,7 +29,6 @@ import logging
|
||||
import operator
|
||||
import pytz
|
||||
import re
|
||||
import time
|
||||
from collections import defaultdict, MutableMapping, OrderedDict
|
||||
from inspect import getmembers, currentframe
|
||||
from operator import attrgetter, itemgetter
|
||||
@@ -65,20 +64,6 @@ onchange_v7 = re.compile(r"^(\w+)\((.*)\)$")
|
||||
|
||||
AUTOINIT_RECALCULATE_STORED_FIELDS = 1000
|
||||
|
||||
# base environment for doing a safe_eval
|
||||
SAFE_EVAL_BASE = {
|
||||
'datetime': datetime,
|
||||
'dateutil': dateutil,
|
||||
'time': time,
|
||||
}
|
||||
|
||||
def make_compute(text, deps):
|
||||
""" Return a compute function from its code body and dependencies. """
|
||||
func = lambda self: safe_eval(text, SAFE_EVAL_BASE, {'self': self}, mode="exec")
|
||||
deps = [arg.strip() for arg in (deps or "").split(",")]
|
||||
return api.depends(*deps)(func)
|
||||
|
||||
|
||||
def check_object_name(name):
|
||||
""" Check if the given name is a valid model name.
|
||||
|
||||
@@ -646,57 +631,13 @@ class BaseModel(object):
|
||||
|
||||
@api.model
|
||||
def _add_manual_fields(self, partial):
|
||||
IrModelFields = self.env['ir.model.fields']
|
||||
manual_fields = self.pool.get_manual_fields(self._cr, self._name)
|
||||
|
||||
for name, field in manual_fields.iteritems():
|
||||
if name in self._fields:
|
||||
continue
|
||||
attrs = {
|
||||
'manual': True,
|
||||
'string': field['field_description'],
|
||||
'help': field['help'],
|
||||
'index': bool(field['index']),
|
||||
'copy': bool(field['copy']),
|
||||
'related': field['related'],
|
||||
'required': bool(field['required']),
|
||||
'readonly': bool(field['readonly']),
|
||||
'store': bool(field['store']),
|
||||
}
|
||||
# FIXME: ignore field['serialization_field_id']
|
||||
if field['ttype'] in ('char', 'text', 'html'):
|
||||
attrs['translate'] = bool(field['translate'])
|
||||
attrs['size'] = field['size'] or None
|
||||
elif field['ttype'] in ('selection', 'reference'):
|
||||
attrs['selection'] = safe_eval(field['selection'])
|
||||
elif field['ttype'] == 'many2one':
|
||||
if partial and field['relation'] not in self.env:
|
||||
continue
|
||||
attrs['comodel_name'] = field['relation']
|
||||
attrs['ondelete'] = field['on_delete']
|
||||
attrs['domain'] = safe_eval(field['domain']) if field['domain'] else None
|
||||
elif field['ttype'] == 'one2many':
|
||||
if partial and not (
|
||||
field['relation'] in self.env and (
|
||||
field['relation_field'] in self.env[field['relation']]._fields or
|
||||
field['relation_field'] in self.pool.get_manual_fields(self._cr, field['relation'])
|
||||
)):
|
||||
continue
|
||||
attrs['comodel_name'] = field['relation']
|
||||
attrs['inverse_name'] = field['relation_field']
|
||||
attrs['domain'] = safe_eval(field['domain']) if field['domain'] else None
|
||||
elif field['ttype'] == 'many2many':
|
||||
if partial and field['relation'] not in self.env:
|
||||
continue
|
||||
attrs['comodel_name'] = field['relation']
|
||||
rel, col1, col2 = self.env['ir.model.fields']._custom_many2many_names(field['model'], field['relation'])
|
||||
attrs['relation'] = field['relation_table'] or rel
|
||||
attrs['column1'] = field['column1'] or col1
|
||||
attrs['column2'] = field['column2'] or col2
|
||||
attrs['domain'] = safe_eval(field['domain']) if field['domain'] else None
|
||||
# add compute function if given
|
||||
if field['compute']:
|
||||
attrs['compute'] = make_compute(field['compute'], field['depends'])
|
||||
self._add_field(name, Field.by_type[field['ttype']](**attrs))
|
||||
for name, field_data in manual_fields.iteritems():
|
||||
if name not in self._fields:
|
||||
field = IrModelFields._instanciate(field_data, partial)
|
||||
if field:
|
||||
self._add_field(name, field)
|
||||
|
||||
@classmethod
|
||||
def _init_constraints_onchanges(cls):
|
||||
|
||||
Reference in New Issue
Block a user