[REM] models: remove _columns
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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):
|
||||
|
||||
@@ -2,4 +2,3 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import osv
|
||||
import fields
|
||||
|
||||
+32
-35
@@ -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
@@ -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')
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user