Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion addons/base_automation/models/base_automation.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ def make_compute_field_value():
#
def _compute_field_value(self, field):
# determine fields that may trigger an action
stored_fields = [f for f in self._field_computed[field] if f.store]
stored_fields = [f for f in self.pool.field_computed[field] if f.store]
if not any(stored_fields):
return _compute_field_value.origin(self, field)
# retrieve the action rules to possibly execute
Expand Down
6 changes: 3 additions & 3 deletions addons/base_sparse_field/models/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def decorate(func):
:param sparse: the name of the field where the value of this field must
be stored.
"""
fields.Field.sparse = None

@monkey_patch(fields.Field)
def _get_attrs(self, model, name):
Expand Down Expand Up @@ -76,11 +77,10 @@ def _inverse_sparse(self, records):
class Serialized(fields.Field):
""" Serialized fields provide the storage for sparse fields. """
type = 'serialized'
_slots = {
'prefetch': False, # not prefetched by default
}
column_type = ('text', 'text')

prefetch = False # not prefetched by default

def convert_to_column(self, value, record, values=None, validate=True):
return self.convert_to_cache(value, record, validate=validate)

Expand Down
60 changes: 37 additions & 23 deletions addons/base_sparse_field/models/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-

from collections import defaultdict

from odoo import models, fields, api, _
from odoo.exceptions import UserError

Expand Down Expand Up @@ -29,33 +31,45 @@ def write(self, vals):

return super(IrModelFields, self).write(vals)

def _reflect_model(self, model):
super(IrModelFields, self)._reflect_model(model)
def _reflect_fields(self, model_names):
super()._reflect_fields(model_names)

# set 'serialization_field_id' on sparse fields; it is done here to
# ensure that the serialized field is reflected already
cr = self._cr
query = """ UPDATE ir_model_fields
SET serialization_field_id=%s
WHERE model=%s AND name=%s
RETURNING id
"""
fields_data = self._existing_field_data(model._name)

for field in model._fields.values():
ser_field_id = None
ser_field_name = getattr(field, 'sparse', None)
if ser_field_name:
if ser_field_name not in fields_data:
msg = _("Serialization field `%s` not found for sparse field `%s`!")
raise UserError(msg % (ser_field_name, field.name))
ser_field_id = fields_data[ser_field_name]['id']

if fields_data[field.name]['serialization_field_id'] != ser_field_id:
cr.execute(query, (ser_field_id, model._name, field.name))
record = self.browse(cr.fetchone())
self.pool.post_init(record.modified, ['serialization_field_id'])
self.clear_caches()

# retrieve existing values
query = """
SELECT model, name, id, serialization_field_id
FROM ir_model_fields
WHERE model IN %s
"""
cr.execute(query, [tuple(model_names)])
Comment thread
rco-odoo marked this conversation as resolved.
Outdated
existing = {row[:2]: row[2:] for row in cr.fetchall()}

# determine updates, grouped by value
updates = defaultdict(list)
for model_name in model_names:
for field_name, field in self.env[model_name]._fields.items():
field_id, current_value = existing[(model_name, field_name)]
try:
value = existing[(model_name, field.sparse)][0] if field.sparse else None
except KeyError:
msg = _("Serialization field %r not found for sparse field %s!")
raise UserError(msg % (field.sparse, field))
if current_value != value:
updates[value].append(field_id)

if not updates:
return

# update fields
query = "UPDATE ir_model_fields SET serialization_field_id=%s WHERE id IN %s"
for value, ids in updates.items():
cr.execute(query, [value, tuple(ids)])
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

execute_batch might be an option here depending how many updates we usually have. I think psycopg 2.7 is required on master / 13.3 so it ought be available.


records = self.browse(id_ for ids in updates.values() for id_ in ids)
self.pool.post_init(records.modified, ['serialization_field_id'])

def _instanciate_attrs(self, field_data):
attrs = super(IrModelFields, self)._instanciate_attrs(field_data)
Expand Down
2 changes: 1 addition & 1 deletion addons/event/models/event_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ def _compute_seats_limited(self):
""" Make it separate from ``_compute_from_event_type`` because otherwise
a value given at create (see create override) would protect all other fields
depending on event type id from being computed as compute method will be
blacklisted during create (see ``_field_computed`` attribute used in create
blacklisted during create (see ``registry.field_computed`` attribute used in create
to compute protected field from re-computation) """
for event in self:
if event.event_type_id.seats_max:
Expand Down
4 changes: 2 additions & 2 deletions addons/mail/models/ir_model_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ class IrModelField(models.Model):
help="If set every modification done to this field is tracked in the chatter. Value is used to order tracking values.",
)

def _reflect_field_params(self, field):
def _reflect_field_params(self, field, model_id):
""" Tracking value can be either a boolean enabling tracking mechanism
on field, either an integer giving the sequence. Default sequence is
set to 100. """
vals = super(IrModelField, self)._reflect_field_params(field)
vals = super(IrModelField, self)._reflect_field_params(field, model_id)
tracking = getattr(field, 'tracking', None)
if tracking is True:
tracking = 100
Expand Down
15 changes: 7 additions & 8 deletions addons/mail/models/mail_alias_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,25 +53,24 @@ def unlink(self):
def _init_column(self, name):
""" Create aliases for existing rows. """
super(AliasMixin, self)._init_column(name)
if name != 'alias_id':
return
if name == 'alias_id':
# as 'mail.alias' records refer to 'ir.model' records, create
# aliases after the reflection of models
self.pool.post_init(self._init_column_alias_id)

def _init_column_alias_id(self):
# both self and the alias model must be present in 'ir.model'
IM = self.env['ir.model']
IM._reflect_model(self)
IM._reflect_model(self.env[self.get_alias_model_name({})])

alias_ctx = {
'alias_model_name': self.get_alias_model_name({}),
'alias_parent_model_name': self._name,
}
alias_model = self.env['mail.alias'].sudo().with_context(alias_ctx).browse([])
alias_model = self.env['mail.alias'].sudo().with_context(alias_ctx)

child_ctx = {
'active_test': False, # retrieve all records
'prefetch_fields': False, # do not prefetch fields on records
}
child_model = self.sudo().with_context(child_ctx).browse([])
child_model = self.sudo().with_context(child_ctx)

for record in child_model.search([('alias_id', '=', False)]):
# create the alias, and link it to the current record
Expand Down
2 changes: 1 addition & 1 deletion addons/mail/models/mail_thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ def write(self, values):

def _compute_field_value(self, field):
if not self._context.get('tracking_disable') and not self._context.get('mail_notrack'):
self._prepare_tracking(f.name for f in self._field_computed[field] if f.store)
self._prepare_tracking(f.name for f in self.pool.field_computed[field] if f.store)

return super()._compute_field_value(field)

Expand Down
Loading