Hi all,

In continuation to the POC and the related discussions in IRC sometime back we 
have a cleaner and flexible proposal.

This would mea that we have a new model class called ModelEAV which inherits 
from ModelStorage and handles attributes.

It was easier to write some code to explain this rather than explain in English 
so a  rough code sketch of the same which was done is below:

This is not a final code but just to have a good understanding. Please do 
review the idea. 

Models:

ir.attribute - Where the attributes for a model are defined
========
model : fields.Many2one('ir.model')
name : fields.Char
type : fields.Selection(
            [
                text/selection/binary/numeric
                ]
            )
selections : fields.One2Many ir.attribute.selections (try using property fields)
active: fields.Boolean
help: fields.Text

Ex:
model: `product.product`
name: `color`
type: `selection`
active: True
help: `Choose the color of the product`

ir.attribute.selections
==============
attribute : fields.Many2One ir.attribute
name : fields.Char 

Ex:

attribute: `color` name: `Red`
attribute: `color` name: `Green`
attribute: `color` name: `Blue`
attribute: `color` name: `White`

ir.attribute.values - Where actual values would be stored
=============
entity : fields.Reference
attribute: fields.Many2One ir.attribute 
value: base fields for storing value
value_text : Wrapper function field
value_selection : Wrapper function field
value_binary : Wrapper function field
value_numeric : Wrapper function field

New Model Abstraction called ModelEAV will be defined where the EAV pattern 
needs to be used.

class ModelEAV(ModelStorage):
    
    attribute_ = fields.One2Many('ir.attribute.values', None)
    
    def create(self, values):
        attribute_values_obj = self.pool.get('ir.attribute.values')
        attributes = None
        if 'attributes_'  in values.keys():
            attributes = values.pop('attributes_')
        res = super(ModelEAV, self).create(values)
        if attributes:
            entity = '%s, %s' % (self._name, res)
            for attribute_values in attributes:
                attribute_values['entity'] = entity
                attribute_values_obj.create(attribute_values)
        return res
    
    def write(self, ids, values):
         attribute_values_obj = self.pool.get('ir.attribute.values')
         attributes=None
         if 'attributes_'  in values.keys():
             attributes = values.pop('attributes_')
        if attributes:
            entity = '%s, %s' % (self._name, res)
            for attribute_values in attributes:
                #Check if attribute already exists
                attribute_value_id = attribute_values_obj.search([
                    ('attribute', '=', attribute_values['attribute']),
                    ('entity', '=', entity)
                    ]
                if attribute_value_id:
                    attribute_values_obj.write(attribute_value_id, 
attribute_values)
                else:
                    attribute_values['entity'] = entity
                    attribute_values_obj.create(attribute_values)
        return super(ModelEAV, self).write(ids, values)

    def delete(ids):
        attribute_values_obj = self.pool.get('ir.attribute.values')
        if isinstance(ids, (int, long)):
            ids = [ids]
        attribute_value_ids = attribute_values_obj.search([('entity', '=', 
entity)])
        if attribute_value_ids:
            attribute_values_obj.delete(attribute_value_ids)
        return super(ModelEAV, self).delete(ids)

    def _view_look_dom_arch(self, tree, type):
        attribute_obj = self.pool.get('ir.attribute')
        attribute_obj.convert_view(tree)
        arch, fields = super(ModelEAV, self)._view_look_dom_arch(tree, type)
        return arch, fields
    
    def fields_get(self, fields_names=None):
        res = super(ModelEAV, self).fields_get(fields_names)
        if 'attribute_' in fields_names:
            #update the one2many_list so that the attribute has a domain on 
this model
        return res
        
    def read(self, ids, fields_names=None):
        single_record = False
        if isinstance(ids, (int, long)):
            single_record = True
            ids = [ids]
        attribute_values_obj = self.pool.get('ir.attribute.values')
        read_attributes = fields_names is None or False
        if 'attributes_' in fields_names:
             fields_names.pop('attributes_')
             read_attributes = True
        res = self.read(ids, fields_names)
        if read_attributes:
            for record in res:
                entity = '%s, %s' %(self._name, record['id'])
                record['attributes_'] = attribute_values_obj.search([('entity', 
'=', entity)])
        if single_record:
            return res[0]
        return res

===============================
So for product.product to use EAV pattern:

from trytond.model import ModelSQL, ModelView, ModelEAV

class ProductProduct(ModelEAV, ModelSQL, ModelView):
        _name = 'product.product'

        regular fields

ProductProduct()

and update the view to use a new tag <attributes />

which will expand into a one2many list view where the attributes are 
shown/edited.

Thanks,

Sharoon Thomas

On 20 Aug 2010, at 01:53, Phillip Heller wrote:

> Ok, so the Attributes you list below are perfect examples, and I do agree 
> that Serial Numbers and other *instance* related values are a function of 
> inventory.
> 
> I suppose this concept is something to propose in a stock_instance module or 
> something of the sort.
> 
> Thanks.
> 
> --phil
> 
> On Aug 19, 2010, at 10:46 AM, Sharoon Thomas wrote:
> 
> <snip>
> 
>> Well i dont think that this EAV model would fit this purpose of a serial 
>> number. However, in other terms this could be generalised. let me stick to 
>> the example of mac book.
>> 
>> Attributes could be:
>> 
>> Screen Size
>> Weight
>> Processor
>> Memory
>> HDD
>> 
>> etc. which remain constant for a product. having a different serial number, 
>> I am not sure is an attribute issue. I think its more of an inventory 
>> tracking issue ?
> 

-- 
[email protected] mailing list

Reply via email to