[REM] models: remove _columns

This commit is contained in:
Raphael Collet
2016-08-31 17:21:53 +02:00
parent 32c762803a
commit 8ea5f49391
17 changed files with 80 additions and 1438 deletions
@@ -34,13 +34,13 @@
<strong>Printing date:</strong><br/>
<span t-esc="time.strftime('%Y-%m-%d')"/>
</div>
<div class="col-xs-3" t-if="'sale_ref' in o._columns.keys()">
<div class="col-xs-3" t-if="'sale_ref' in o">
<strong>Partner Ref:</strong><br/>
<span t-esc="'sale_ref' in o._columns.keys() and o.sale_ref"/>
<span t-esc="'sale_ref' in o and o.sale_ref"/>
</div>
<div class="col-xs-3" t-if="'sale_name' in o._columns.keys()">
<div class="col-xs-3" t-if="'sale_name' in o">
<strong>SO Number:</strong><br/>
<span t-esc="'sale_name' in o._columns.keys() and o.sale_name"/>
<span t-esc="'sale_name' in o and o.sale_name"/>
</div>
</div>
+2 -2
View File
@@ -43,7 +43,7 @@ class TestSurvey(TransactionCase):
self.assertEqual(question.question, "Q0", msg="Title of the Question is somehow modified.")
def test_01_question_type_validation_save_line_function(self):
for (question_type, text) in self.env['survey.question']._columns['type'].selection:
for (question_type, text) in self.env['survey.question']._fields['type'].selection:
# Each question ype must have validation function.
self.assertTrue(hasattr(self.env['survey.question'], 'validate_' + question_type), msg="Question must have a validation method in\
the form of 'validate_' followed by the name of the type.")
@@ -53,7 +53,7 @@ class TestSurvey(TransactionCase):
the form of 'save_line_' followed by the name of the type.")
def test_02_question_answer_required(self):
for (question_type, text) in self.env['survey.question']._columns['type'].selection:
for (question_type, text) in self.env['survey.question']._fields['type'].selection:
# Blank value of field is not accepted for mandatory questions.
if question_type == 'multiple_choice':
question = self.env['survey.question'].sudo(self.survey_manager).create({
-3
View File
@@ -22,9 +22,6 @@ class TestACL(TransactionCase):
def _set_field_groups(self, model, field_name, groups):
field = model._fields[field_name]
self.patch(field, 'groups', groups)
if field.column:
self.patch(field.column, 'groups', groups)
self.patch(field.column, '_prefetch', False)
def test_field_visibility_restriction(self):
"""Check that model-level ``groups`` parameter effectively restricts access to that
-1
View File
@@ -442,7 +442,6 @@ class TestParentStore(TransactionCase):
# force res_partner_category.copy() to copy children
category = self.env['res.partner.category']
self.patch(category._fields['child_ids'], 'copy', True)
self.patch(category._columns['child_ids'], 'copy', True)
# setup categories
self.root = category.create({'name': 'Root category'})
@@ -641,11 +641,9 @@ class TestAutoJoin(TransactionCase):
# Get test columns
def patch_auto_join(model, fname, value):
self.patch(model._fields[fname], 'auto_join', value)
self.patch(model._columns[fname], '_auto_join', value)
def patch_domain(model, fname, value):
self.patch(model._fields[fname], 'domain', value)
self.patch(model._columns[fname], '_domain', value)
# Get country/state data
country_us = self.env['res.country'].search([('code', 'like', 'US')], limit=1)
@@ -67,8 +67,6 @@ class test_inherits(common.TransactionCase):
# the extra values are added, both in the field and the column
self.assertEqual(mother._fields['state'].selection,
[('a', 'A'), ('b', 'B'), ('c', 'C'), ('d', 'D')])
self.assertEqual(mother._columns['state'].selection,
[('a', 'A'), ('b', 'B'), ('c', 'C'), ('d', 'D')])
def test_50_search_one2many(self):
""" check search on one2many field based on inherited many2one field. """
@@ -2,7 +2,6 @@
from . import test_new_fields
from . import test_onchange
from . import test_field_conversions
from . import test_attributes
from . import test_ui
from . import test_domain
@@ -1,14 +0,0 @@
# -*- coding: utf-8 -*-
from openerp import fields
from openerp.tests import common
class TestFieldToColumn(common.TransactionCase):
def test_char(self):
# create a field, initialize its attributes, and convert it to a column
field = fields.Char(string="test string", required=True)
field.setup_base(self.env['res.partner'], 'test')
column = field.to_column()
self.assertEqual(column.string, "test string")
self.assertTrue(column.required)
@@ -68,7 +68,6 @@ class TestFields(common.TransactionCase):
self.assertFalse(field.store)
self.assertFalse(field.compute)
self.assertFalse(field.inverse)
self.assertFalse(field.column)
# find messages
for message in self.env['test_new_api.message'].search([]):
+9 -110
View File
@@ -104,13 +104,10 @@ class MetaField(type):
MetaField.by_type[cls.type] = cls
# compute class attributes to avoid calling dir() on fields
cls.column_attrs = []
cls.related_attrs = []
cls.description_attrs = []
for attr in dir(cls):
if attr.startswith('_column_'):
cls.column_attrs.append((attr[8:], attr))
elif attr.startswith('_related_'):
if attr.startswith('_related_'):
cls.related_attrs.append((attr[9:], attr))
elif attr.startswith('_description_'):
cls.description_attrs.append((attr[13:], attr))
@@ -306,8 +303,6 @@ class Field(object):
'automatic': False, # whether the field is automatically created ("magic" field)
'inherited': False, # whether the field is inherited (_inherits)
'origin': None, # the column from which the field was created
'column': None, # the column corresponding to the field
'name': None, # name of the field
'model_name': None, # name of the model of this field
@@ -733,7 +728,7 @@ class Field(object):
@property
def _description_searchable(self):
return bool(self.store or self.search or (self.column and self.column._fnct_search))
return bool(self.store or self.search)
@property
def _description_sortable(self):
@@ -753,52 +748,6 @@ class Field(object):
return field_help.get(self.name) or self.help
return self.help
############################################################################
#
# Conversion to column instance
#
def to_column(self):
""" Return a column object corresponding to ``self``, or ``None``. """
if self.column:
return self.column
if not self.store and (self.compute or not self.origin):
# non-stored computed fields do not have a corresponding column
return None
# determine column parameters
#_logger.debug("Create fields._column for Field %s", self)
args = {}
for attr, prop in self.column_attrs:
args[attr] = getattr(self, prop)
for attr, value in self._attrs.iteritems():
args[attr] = value
if self.origin:
# let the origin provide a valid column for the given parameters
self.column = self.origin.new(_computed_field=bool(self.compute), **args)
else:
# create a fresh new column of the right type
self.column = getattr(fields, self.type)(**args)
return self.column
# properties used by to_column() to create a column instance
_column__module = property(attrgetter('_module'))
_column_copy = property(attrgetter('copy'))
_column_select = property(attrgetter('index'))
_column_manual = property(attrgetter('manual'))
_column_string = property(attrgetter('string'))
_column_help = property(attrgetter('help'))
_column_readonly = property(attrgetter('readonly'))
_column_required = property(attrgetter('required'))
_column_states = property(attrgetter('states'))
_column_groups = property(attrgetter('groups'))
_column_change_default = property(attrgetter('change_default'))
_column_deprecated = property(attrgetter('deprecated'))
_column_group_operator = property(attrgetter('group_operator'))
############################################################################
#
# Conversion of values
@@ -984,7 +933,7 @@ class Field(object):
""" Determine the value of ``self`` for ``record``. """
env = record.env
if self.column and not (self.compute and env.in_onchange):
if self.store and not (self.compute and env.in_onchange):
# this is a stored field or an old-style function field
if self.compute:
# this is a stored computed field, check for recomputation
@@ -1209,12 +1158,8 @@ class Float(Field):
return self._digits
_related__digits = property(attrgetter('_digits'))
_description_digits = property(attrgetter('digits'))
_column_digits = property(lambda self: not callable(self._digits) and self._digits)
_column_digits_compute = property(lambda self: callable(self._digits) and self._digits)
def convert_to_column(self, value, record):
result = float(value or 0.0)
digits = self.digits
@@ -1254,11 +1199,8 @@ class Monetary(Field):
super(Monetary, self).__init__(string=string, currency_field=currency_field, **kwargs)
_related_currency_field = property(attrgetter('currency_field'))
_description_currency_field = property(attrgetter('currency_field'))
_column_currency_field = property(attrgetter('currency_field'))
def _setup_regular_base(self, model):
super(Monetary, self)._setup_regular_base(model)
if not self.currency_field:
@@ -1298,7 +1240,6 @@ class _String(Field):
kwargs['translate'] = bool(kwargs['translate'])
super(_String, self).__init__(string=string, **kwargs)
_column_translate = property(attrgetter('translate'))
_related_translate = property(attrgetter('translate'))
def _description_translate(self, env):
@@ -1364,7 +1305,6 @@ class Char(_String):
def column_type(self):
return ('varchar', pg_varchar(self.size))
_column_size = property(attrgetter('size'))
_related_size = property(attrgetter('size'))
_description_size = property(attrgetter('size'))
@@ -1427,28 +1367,18 @@ class Html(_String):
if self.translate is True and self.sanitize:
self.translate = html_translate
_column_sanitize = property(attrgetter('sanitize'))
_related_sanitize = property(attrgetter('sanitize'))
_description_sanitize = property(attrgetter('sanitize'))
_column_sanitize_tags = property(attrgetter('sanitize_tags'))
_related_sanitize_tags = property(attrgetter('sanitize_tags'))
_description_sanitize_tags = property(attrgetter('sanitize_tags'))
_column_sanitize_attributes = property(attrgetter('sanitize_attributes'))
_related_sanitize_attributes = property(attrgetter('sanitize_attributes'))
_description_sanitize_attributes = property(attrgetter('sanitize_attributes'))
_column_sanitize_style = property(attrgetter('sanitize_style'))
_related_sanitize_style = property(attrgetter('sanitize_style'))
_description_sanitize_style = property(attrgetter('sanitize_style'))
_column_strip_style = property(attrgetter('strip_style'))
_related_strip_style = property(attrgetter('strip_style'))
_description_strip_style = property(attrgetter('strip_style'))
_column_strip_classes = property(attrgetter('strip_classes'))
_related_strip_classes = property(attrgetter('strip_classes'))
_description_sanitize = property(attrgetter('sanitize'))
_description_sanitize_tags = property(attrgetter('sanitize_tags'))
_description_sanitize_attributes = property(attrgetter('sanitize_attributes'))
_description_sanitize_style = property(attrgetter('sanitize_style'))
_description_strip_style = property(attrgetter('strip_style'))
_description_strip_classes = property(attrgetter('strip_classes'))
def convert_to_column(self, value, record):
@@ -1627,7 +1557,6 @@ class Binary(Field):
def column_type(self):
return None if self.attachment else ('bytea', 'bytea')
_column_attachment = property(attrgetter('attachment'))
_description_attachment = property(attrgetter('attachment'))
def convert_to_column(self, value, record):
@@ -1766,14 +1695,6 @@ class Selection(Field):
else:
return selection
@property
def _column_selection(self):
if isinstance(self.selection, basestring):
method = self.selection
return lambda self, *a, **kw: getattr(self, method)(*a, **kw)
else:
return self.selection
def get_values(self, env):
""" return a list of the possible values """
selection = self.selection
@@ -1872,10 +1793,6 @@ class _Relational(Field):
def _description_domain(self, env):
return self.domain(env[self.model_name]) if callable(self.domain) else self.domain
_column_obj = property(attrgetter('comodel_name'))
_column_domain = property(attrgetter('domain'))
_column_context = property(attrgetter('context'))
def null(self, record):
return record.env[self.comodel_name]
@@ -1930,9 +1847,6 @@ class Many2one(_Relational):
if not self.delegate:
self.delegate = name in model._inherits.values()
_column_ondelete = property(attrgetter('ondelete'))
_column_auto_join = property(attrgetter('auto_join'))
def _update(self, records, value):
""" Update the cached value of ``self`` for ``records`` with ``value``.
This is used to reflect the assignment ``value[name] = records``, where
@@ -2181,10 +2095,6 @@ class One2many(_RelationalMulti):
_description_relation_field = property(attrgetter('inverse_name'))
_column_fields_id = property(attrgetter('inverse_name'))
_column_auto_join = property(attrgetter('auto_join'))
_column_limit = property(attrgetter('limit'))
def convert_to_onchange(self, value, record, fnames=()):
if fnames:
# do not serialize self's inverse field
@@ -2342,12 +2252,6 @@ class Many2many(_RelationalMulti):
# add self in m2m, so that its inverse field can find it
m2m[(self.relation, self.column1, self.column2)] = self
_column_rel = property(attrgetter('relation'))
_column_id1 = property(attrgetter('column1'))
_column_id2 = property(attrgetter('column2'))
_column_auto_join = property(attrgetter('auto_join'))
_column_limit = property(attrgetter('limit'))
def check_schema(self, model):
cr = model._cr
rel, id1, id2 = self.relation, self.column1, self.column2
@@ -2481,10 +2385,6 @@ class Id(Field):
'readonly': True,
}
def to_column(self):
self.column = fields.integer(self.string)
return self.column
def __get__(self, record, owner):
if record is None:
return self # the field is accessed through the class owner
@@ -2499,4 +2399,3 @@ class Id(Field):
from openerp import SUPERUSER_ID
from .exceptions import AccessError, MissingError, UserError
from .models import check_pg_name, BaseModel, IdType
from .osv import fields
+21 -57
View File
@@ -46,7 +46,6 @@ from . import api
from . import tools
from .api import Environment
from .exceptions import AccessError, MissingError, ValidationError, UserError
from .osv import fields
from .osv.query import Query
from .tools import frozendict, lazy_property, ormcache, Collector, LastOrderedSet, OrderedSet
from .tools.config import config
@@ -170,13 +169,6 @@ class MetaModel(api.Meta):
if isinstance(val, Field):
val.args = dict(val.args, _module=self._module)
# transform columns into new-style fields (enables field inheritance)
for name, column in self._columns.iteritems():
if name in self.__dict__:
_logger.warning("In class %s, field %r overriding an existing value", self, name)
column._module = self._module
setattr(self, name, column.to_field())
def _get_addon_name(self, full_name):
# The (OpenERP) module name can be in the ``openerp.addons`` namespace
# or not. For instance, module ``sale`` can be imported as
@@ -246,7 +238,6 @@ class BaseModel(object):
_inherit = None # Python-inherited models ('model' or ['model'])
_inherits = {} # inherited models {'parent_model': 'm2o_field'}
_columns = {} # field definitions (old API)
_constraints = [] # Python constraints (old API)
_table = None # SQL table name used by model
@@ -388,8 +379,6 @@ class BaseModel(object):
# basic setup of field
field.setup_base(self, name)
# cls._columns will be updated once fields are fully set up
@api.model
def _pop_field(self, name):
""" Remove the field with the given ``name`` from the model.
@@ -397,7 +386,6 @@ class BaseModel(object):
"""
cls = type(self)
field = cls._fields.pop(name)
cls._columns.pop(name, None)
if hasattr(cls, name):
delattr(cls, name)
return field
@@ -743,7 +731,6 @@ class BaseModel(object):
- copy the stored fields' functions in the registry,
- retrieve custom fields and add them in the model,
- ensure there is a many2one for each _inherits'd parent,
- update the children's _columns,
- give a chance to each field to initialize itself.
"""
@@ -1997,19 +1984,17 @@ class BaseModel(object):
for gb in groupby_fields:
assert gb in fields, "Fields in 'groupby' must appear in the list of fields to read (perhaps it's missing in the list view?)"
assert gb in self._fields, "Unknown field %r in 'groupby'" % gb
groupby_def = self._fields[gb].base_field.column
assert groupby_def and groupby_def._classic_write, "Fields in 'groupby' must be regular database-persisted fields (no function or related fields), or function fields with store=True"
if not (gb in self._fields):
# Don't allow arbitrary values, as this would be a SQL injection vector!
raise UserError(_('Invalid group_by specification: "%s".\nA group_by specification must be a list of valid fields.') % (gb,))
gb_field = self._fields[gb].base_field
assert gb_field.store and gb_field.column_type, "Fields in 'groupby' must be regular database-persisted fields (no function or related fields), or function fields with store=True"
aggregated_fields = [
f for f in fields
if f != 'sequence'
if f not in groupby_fields
if f in self._fields
if self._fields[f].group_operator
if getattr(self._fields[f].base_field.column, '_classic_write', False)
for field in [self._fields.get(f)]
if field
if field.group_operator
if field.base_field.store and field.base_field.column_type
]
field_formatter = lambda f: (
@@ -2871,8 +2856,7 @@ class BaseModel(object):
""" Setup the fields, except for recomputation triggers. """
cls = type(self)
# set up fields, and determine their corresponding column
cls._columns = {}
# set up fields
bad_fields = []
for name, field in cls._fields.iteritems():
try:
@@ -2886,9 +2870,6 @@ class BaseModel(object):
bad_fields.append(name)
continue
raise
column = field.to_column()
if column:
cls._columns[name] = column
for name in bad_fields:
del cls._fields[name]
@@ -3137,7 +3118,7 @@ class BaseModel(object):
fields_pre = [
field
for field in fields
if field.base_field.column._classic_write
if field.base_field.store and field.base_field.column_type
if not (field.inherited and callable(field.base_field.translate))
]
@@ -3197,9 +3178,9 @@ class BaseModel(object):
# Warn about deprecated fields now that fields_pre and fields_post are computed
for f in field_names:
column = self._columns[f]
if column.deprecated:
_logger.warning('Field %s.%s is deprecated: %s', self._name, f, column.deprecated)
field = self._fields[f]
if field.deprecated:
_logger.warning('Field %s is deprecated: %s', field, field.deprecated)
# store failed values in cache for the records that could not be read
missing = self - fetched
@@ -3580,7 +3561,7 @@ class BaseModel(object):
for key, val in vals.iteritems():
field = self._fields.get(key)
if field:
if field.column or field.inherited:
if field.store or field.inherited:
old_vals[key] = val
if field.inverse and not field.inherited:
new_vals[key] = val
@@ -3896,7 +3877,7 @@ class BaseModel(object):
elif field.inherited:
tocreate[field.related_field.model_name][name] = val
del vals[name]
elif not field.column:
elif not field.store:
del vals[name]
elif field.inverse:
protected_fields.append(field)
@@ -4143,12 +4124,10 @@ class BaseModel(object):
# also add missing joins for reaching the table containing the m2o field
qualified_field = self._inherits_join_calc(alias, order_field, query)
alias, order_field = qualified_field.replace('"', '').split('.', 1)
column = field.base_field.column
else:
column = field.column
field = field.base_field
assert field.type == 'many2one', 'Invalid field passed to _generate_m2o_order_by()'
if not (column and column._classic_write):
if not field.store:
_logger.debug("Many2one function/related fields must be stored "
"to be used as ordering fields! Ignoring sorting for %s.%s",
self._name, order_field)
@@ -4192,17 +4171,16 @@ class BaseModel(object):
else:
if field.inherited:
field = field.base_field
column = field.column
if column and column._classic_read:
qualifield_name = self._inherits_join_calc(alias, order_field, query, implicit=False, outer=True)
if field.type == 'boolean':
qualifield_name = "COALESCE(%s, false)" % qualifield_name
order_by_elements.append("%s %s" % (qualifield_name, order_direction))
elif column and column._type == 'many2one':
if field.store and field.type == 'many2one':
key = (field.model_name, field.comodel_name, order_field)
if key not in seen:
seen.add(key)
order_by_elements += self._generate_m2o_order_by(alias, order_field, query, do_reverse, seen)
elif field.store and field.column_type:
qualifield_name = self._inherits_join_calc(alias, order_field, query, implicit=False, outer=True)
if field.type == 'boolean':
qualifield_name = "COALESCE(%s, false)" % qualifield_name
order_by_elements.append("%s %s" % (qualifield_name, order_direction))
else:
continue # ignore non-readable or "non-joinable" fields
@@ -4273,20 +4251,6 @@ class BaseModel(object):
return _uniquify_list([x[0] for x in res])
@api.model
def distinct_field_get(self, field, value, args=None, offset=0, limit=None):
""" Returns the different values ever entered for one field. This is used,
for example, in the client when the user hits enter on a char field.
Deprecated.
"""
ffield = self._fields[field]
if ffield.inherited:
parent_model = ffield.related_field.model_name
return self.env[parent_model].distinct_field_get(field, value, args, offset, limit)
else:
return ffield.column.search(self._cr, self._model, args or [], field, value, offset, limit, self._uid)
@api.multi
@api.returns(None, lambda value: value[0])
def copy_data(self, default=None):
-1
View File
@@ -2,4 +2,3 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import osv
import fields
+32 -35
View File
@@ -121,8 +121,6 @@ from functools import partial
from zlib import crc32
import openerp.modules
from . import fields
from .. import SUPERUSER_ID
from ..models import MAGIC_COLUMNS, BaseModel
import openerp.tools as tools
@@ -796,7 +794,6 @@ class expression(object):
model = leaf.model
field = model._fields.get(path[0])
column = getattr(field, 'column', None)
comodel = model.env.get(getattr(field, 'comodel_name', None))
# ----------------------------------------
@@ -839,7 +836,7 @@ class expression(object):
new_leaf = create_substitution_leaf(leaf, dom_leaf, model)
push(new_leaf)
elif not column and path[0] in MAGIC_COLUMNS:
elif path[0] in MAGIC_COLUMNS:
push_result(leaf)
# ----------------------------------------
@@ -855,14 +852,14 @@ class expression(object):
# as after transforming the column, it will go through this loop once again
# ----------------------------------------
elif len(path) > 1 and column and column._type == 'many2one' and column._auto_join:
elif len(path) > 1 and field.store and field.type == 'many2one' and field.auto_join:
# res_partner.state_id = res_partner__state_id.id
leaf.add_join_context(comodel, path[0], 'id', path[0])
push(create_substitution_leaf(leaf, (path[1], operator, right), comodel))
elif len(path) > 1 and column and column._type == 'one2many' and column._auto_join:
elif len(path) > 1 and field.store and field.type == 'one2many' and field.auto_join:
# res_partner.id = res_partner__bank_ids.partner_id
leaf.add_join_context(comodel, 'id', column._fields_id, path[0])
leaf.add_join_context(comodel, 'id', field.inverse_name, path[0])
domain = field.domain(model) if callable(field.domain) else field.domain
push(create_substitution_leaf(leaf, (path[1], operator, right), comodel))
if domain:
@@ -871,22 +868,22 @@ class expression(object):
push(create_substitution_leaf(leaf, elem, comodel))
push(create_substitution_leaf(leaf, AND_OPERATOR, comodel))
elif len(path) > 1 and column and column._auto_join:
raise NotImplementedError('_auto_join attribute not supported on many2many column %s' % left)
elif len(path) > 1 and field.store and field.auto_join:
raise NotImplementedError('auto_join attribute not supported on field %s' % field)
elif len(path) > 1 and column and column._type == 'many2one':
elif len(path) > 1 and field.store and field.type == 'many2one':
right_ids = comodel.with_context(active_test=False).search([('.'.join(path[1:]), operator, right)]).ids
leaf.leaf = (path[0], 'in', right_ids)
push(leaf)
# Making search easier when there is a left operand as column.o2m or column.m2m
elif len(path) > 1 and column and column._type in ['many2many', 'one2many']:
# Making search easier when there is a left operand as one2many or many2many
elif len(path) > 1 and field.store and field.type in ('many2many', 'one2many'):
right_ids = comodel.search([('.'.join(path[1:]), operator, right)]).ids
table_ids = model.with_context(active_test=False).search([(path[0], 'in', right_ids)]).ids
leaf.leaf = ('id', 'in', table_ids)
push(leaf)
elif not column:
elif not field.store:
# Non-stored field should provide an implementation of search.
if not field.search:
# field does not support search!
@@ -914,22 +911,22 @@ class expression(object):
# -------------------------------------------------
# Applying recursivity on field(one2many)
elif column._type == 'one2many' and operator in HIERARCHY_FUNCS:
elif field.type == 'one2many' and operator in HIERARCHY_FUNCS:
ids2 = to_ids(right, comodel)
if column._obj != model._name:
dom = HIERARCHY_FUNCS[operator](left, ids2, comodel, prefix=column._obj)
if field.comodel_name != model._name:
dom = HIERARCHY_FUNCS[operator](left, ids2, comodel, prefix=field.comodel_name)
else:
dom = HIERARCHY_FUNCS[operator]('id', ids2, model, parent=left)
for dom_leaf in reversed(dom):
push(create_substitution_leaf(leaf, dom_leaf, model))
elif column._type == 'one2many':
elif field.type == 'one2many':
call_null = True
if right is not False:
if isinstance(right, basestring):
op = {'!=': '=', 'not like': 'like', 'not ilike': 'ilike'}.get(operator, operator)
domain = column._domain
domain = field.domain
if callable(domain):
domain = domain(model)
ids2 = [x[0] for x in comodel.name_search(right, domain or [], op, limit=None)]
@@ -946,12 +943,12 @@ class expression(object):
call_null = False
push(create_substitution_leaf(leaf, FALSE_LEAF, model))
else:
# determine ids1 <-- column._fields_id --- ids2
if comodel._fields[column._fields_id].store:
ids1 = select_from_where(cr, column._fields_id, comodel._table, 'id', ids2, operator)
# determine ids1 <-- field.inverse_name --- ids2
if comodel._fields[field.inverse_name].store:
ids1 = select_from_where(cr, field.inverse_name, comodel._table, 'id', ids2, operator)
else:
recs = comodel.browse(ids2).sudo().with_context(prefetch_fields=False)
ids1 = recs.mapped(column._fields_id).ids
ids1 = recs.mapped(field.inverse_name).ids
if ids1:
call_null = False
o2m_op = 'not in' if operator in NEGATIVE_TERM_OPERATORS else 'in'
@@ -963,9 +960,9 @@ class expression(object):
if call_null:
o2m_op = 'in' if operator in NEGATIVE_TERM_OPERATORS else 'not in'
push(create_substitution_leaf(leaf, ('id', o2m_op, select_distinct_from_where_not_null(cr, column._fields_id, comodel._table)), model))
push(create_substitution_leaf(leaf, ('id', o2m_op, select_distinct_from_where_not_null(cr, field.inverse_name, comodel._table)), model))
elif column._type == 'many2many':
elif field.type == 'many2many':
rel_table, rel_id1, rel_id2 = field.relation, field.column1, field.column2
if operator in HIERARCHY_FUNCS:
@@ -983,7 +980,7 @@ class expression(object):
if right is not False:
if isinstance(right, basestring):
op = {'!=': '=', 'not like': 'like', 'not ilike': 'ilike'}.get(operator, operator)
domain = column._domain
domain = field.domain
if callable(domain):
domain = domain(model)
res_ids = [x[0] for x in comodel.name_search(right, domain or [], op, limit=None)]
@@ -1010,11 +1007,11 @@ class expression(object):
m2m_op = 'in' if operator in NEGATIVE_TERM_OPERATORS else 'not in'
push(create_substitution_leaf(leaf, ('id', m2m_op, select_distinct_from_where_not_null(cr, rel_id1, rel_table)), model))
elif column._type == 'many2one':
elif field.type == 'many2one':
if operator in HIERARCHY_FUNCS:
ids2 = to_ids(right, comodel)
if column._obj != model._name:
dom = HIERARCHY_FUNCS[operator](left, ids2, comodel, prefix=column._obj)
if field.comodel_name != model._name:
dom = HIERARCHY_FUNCS[operator](left, ids2, comodel, prefix=field.comodel_name)
else:
dom = HIERARCHY_FUNCS[operator]('id', ids2, model, parent=left)
for dom_leaf in reversed(dom):
@@ -1048,7 +1045,7 @@ class expression(object):
# -> check for null only
# -------------------------------------------------
elif column._type == 'binary' and column.attachment:
elif field.type == 'binary' and field.attachment:
if operator in ('=', '!=') and not right:
inselect_operator = 'inselect' if operator in NEGATIVE_TERM_OPERATORS else 'not inselect'
subselect = "SELECT res_id FROM ir_attachment WHERE res_model=%s AND res_field=%s"
@@ -1056,7 +1053,7 @@ class expression(object):
push(create_substitution_leaf(leaf, ('id', inselect_operator, (subselect, params)), model, internal=True))
else:
_logger.error("Binary field '%s' stored in attachment: ignore %s %s %s",
column.string, left, operator, right)
field.string, left, operator, right)
leaf.leaf = TRUE_LEAF
push(leaf)
@@ -1068,7 +1065,7 @@ class expression(object):
# -------------------------------------------------
else:
if column._type == 'datetime' and right and len(right) == 10:
if field.type == 'datetime' and right and len(right) == 10:
if operator in ('>', '<='):
right += ' 23:59:59'
else:
@@ -1200,7 +1197,7 @@ class expression(object):
else: # Must not happen
raise ValueError("Invalid domain term %r" % (leaf,))
elif (left in model._columns) and model._columns[left]._type == "boolean" and ((operator == '=' and right is False) or (operator == '!=' and right is True)):
elif left in model and model._fields[left].type == "boolean" and ((operator == '=' and right is False) or (operator == '!=' and right is True)):
query = '(%s."%s" IS NULL or %s."%s" = false )' % (table_alias, left, table_alias, left)
params = []
@@ -1208,7 +1205,7 @@ class expression(object):
query = '%s."%s" IS NULL ' % (table_alias, left)
params = []
elif (left in model._columns) and model._columns[left]._type == "boolean" and ((operator == '!=' and right is False) or (operator == '==' and right is True)):
elif left in model and model._fields[left].type == "boolean" and ((operator == '!=' and right is False) or (operator == '==' and right is True)):
query = '(%s."%s" IS NOT NULL and %s."%s" != false)' % (table_alias, left, table_alias, left)
params = []
@@ -1235,7 +1232,7 @@ class expression(object):
sql_operator = {'=like': 'like', '=ilike': 'ilike'}.get(operator, operator)
cast = '::text' if sql_operator.endswith('like') else ''
if left in model._columns:
if left in model:
format = need_wildcard and '%s' or model._fields[left].column_format
unaccent = self._unaccent if sql_operator.endswith('like') else lambda x: x
column = '%s.%s' % (table_alias, _quote(left))
@@ -1256,7 +1253,7 @@ class expression(object):
str_utf8 = str(right)
params = '%%%s%%' % str_utf8
add_null = not str_utf8
elif left in model._columns:
elif left in model:
params = model._fields[left].convert_to_column(right, model)
if add_null:
File diff suppressed because it is too large Load Diff
+4 -7
View File
@@ -18,8 +18,8 @@ import openerp.tools as tools
from . import common
from . import preprocess
from .interface import report_rml
from openerp import fields
from openerp.exceptions import AccessError
from openerp.osv.fields import float as float_field, datetime as datetime_field
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
from openerp.tools.safe_eval import safe_eval
from openerp.tools.translate import _
@@ -177,7 +177,7 @@ class rml_parse(object):
else:
d = res_digits(self.cr)[1]
elif (hasattr(obj, '_field') and\
isinstance(obj._field, float_field) and\
obj._field.type == 'float' and\
obj._field.digits):
d = obj._field.digits[1]
if not d and d is not 0:
@@ -220,9 +220,8 @@ class rml_parse(object):
date = datetime(*value.timetuple()[:6])
if date_time:
# Convert datetime values to the expected client/context timezone
date = datetime_field.context_timestamp(self.cr, self.uid,
timestamp=date,
context=self.localcontext)
record = self.env['base'].with_context(self.localcontext)
date = fields.Datetime.context_timestamp(record, date)
return date.strftime(date_format.encode('utf-8'))
res = self.lang_dict['lang_obj'].format('%.' + str(digits) + 'f', value, grouping=grouping, monetary=monetary)
@@ -332,7 +331,6 @@ class report_sxw(report_rml, preprocess.report):
if self.internal_header:
context.update(internal_header=self.internal_header)
# skip osv.fields.sanitize_binary_value() because we want the raw bytes in all cases
context.update(bin_raw=True)
env = openerp.api.Environment(cr, uid, context)
env['res.font'].sudo().font_scan(lazy=True)
@@ -471,7 +469,6 @@ class report_sxw(report_rml, preprocess.report):
# if binary content was passed as unicode, we must
# re-encode it as a 8-bit string using the pass-through
# 'latin1' encoding, to restore the original byte values.
# See also osv.fields.sanitize_binary_value()
binary_report_content = report_xml.report_sxw_content.encode("latin1")
sxw_io = StringIO.StringIO(binary_report_content)
@@ -1,17 +1,13 @@
# -*- coding: utf-8 -*-
import openerp
from openerp.tools.translate import _
class m(openerp.osv.orm.TransientModel):
""" A model to provide source strings.
"""
from openerp import models, fields, _
class m(models.TransientModel):
""" A model to provide source strings. """
_name = 'test.translation.import'
_columns = {
'name': openerp.osv.fields.char(
'1XBUO5PUYH2RYZSA1FTLRYS8SPCNU1UYXMEYMM25ASV7JC2KTJZQESZYRV9L8CGB',
size=32, help='Efgh'),
}
name = fields.Char('1XBUO5PUYH2RYZSA1FTLRYS8SPCNU1UYXMEYMM25ASV7JC2KTJZQESZYRV9L8CGB',
size=32, help='Efgh')
_('Ijkl')
+2 -2
View File
@@ -102,8 +102,8 @@ def _eval_xml(self, node, env):
ids = env[f_model].search(q).ids
if f_use != 'id':
ids = map(lambda x: x[f_use], env[f_model].browse(ids).read([f_use]))
_cols = env[f_model]._columns
if (f_name in _cols) and _cols[f_name]._type=='many2many':
_fields = env[f_model]._fields
if (f_name in _fields) and _fields[f_name].type == 'many2many':
return ids
f_val = False
if len(ids):