Merge lp:~vauxoo/openobject-server/trunk_field_property_searcheable-dev-hbto into lp:openobject-server

Proposed by hbto [Vauxoo] http://www.vauxoo.com
Status: Needs review
Proposed branch: lp:~vauxoo/openobject-server/trunk_field_property_searcheable-dev-hbto
Merge into: lp:openobject-server
Diff against target: 155 lines (+137/-1)
1 file modified
openerp/osv/fields.py (+137/-1)
To merge this branch: bzr merge lp:~vauxoo/openobject-server/trunk_field_property_searcheable-dev-hbto
Reviewer Review Type Date Requested Status
Lionel Sausin - Initiatives/Numérigraphe (community) no code review - feature is needed. Abstain
Olivier Dony (Odoo) Pending
OpenERP Driver Pending
Review via email: mp+204357@code.launchpad.net

Description of the change

Fixes the issue: ORM Search Method is not working properly on model with property fields

Allowing to search each one of the property fields declared with openerp,

To post a comment you must log in.
Revision history for this message
Lionel Sausin - Initiatives/Numérigraphe (ls-initiatives) wrote :

We need this. For lack of this feature, workarounds have been implemented in many modules, usually doing the search in a python loop over browse records, which is a technical nonsense.

I will not comment on the MP itself because it's a bit complex and I'd need time I can't afford to spend now; I'll just abstain.
But we do need this feature, so please let us know soon if it can be implemented in v8, or if we need to move this proposed implementation to a community module.

review: Abstain (no code review - feature is needed.)

Unmerged revisions

5051. By hbto [Vauxoo] http://www.vauxoo.com

[FIX] Allows property fields be searchable

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openerp/osv/fields.py'
2--- openerp/osv/fields.py 2014-01-23 09:46:46 +0000
3+++ openerp/osv/fields.py 2014-01-31 22:15:14 +0000
4@@ -1470,6 +1470,142 @@
5 domain = [('res_id', 'in', vids)] + domain
6 return prop.search(cr, uid, domain, context=context)
7
8+ def _fnct_search(self, tobj, cr, uid, obj, prop_name, args, context=None):
9+ context = context or {}
10+ prop = obj.pool.get('ir.property')
11+ # get the default values (for res_id = False) for the property fields
12+ default_val = self._get_default(obj, cr, uid, prop_name, context)
13+
14+ res = []
15+
16+ property_field = obj._all_columns.get(prop_name).column
17+ def_id = self._field_get(cr, uid, obj._name, prop_name)
18+ company = obj.pool.get('res.company')
19+ cid = company._company_default_get(cr, uid, obj._name, def_id,
20+ context=context)
21+ propdef = obj.pool.get('ir.model.fields').browse(cr, uid, def_id,
22+ context=context)
23+ from_clause = 'ir_property'
24+ where = " WHERE " + \
25+ "name = '%s' AND "% propdef.name + \
26+ "res_id like '%s,%%' AND "% obj._name + \
27+ "company_id = %s AND "% cid + \
28+ "fields_id = %s AND "% def_id + \
29+ "type = '%s'"% self._type
30+
31+ model_ids = []
32+
33+ type2field = {
34+ 'char': 'value_text', #
35+ 'float': 'value_float', #
36+ 'boolean' : 'value_integer', #
37+ 'integer': 'value_integer', #
38+ 'text': 'value_text', #
39+ 'binary': 'value_binary',
40+ 'many2one': 'value_reference', #
41+ 'date' : 'value_datetime', #
42+ 'datetime' : 'value_datetime', #
43+ }
44+ ghost = False
45+ where_str = ''
46+
47+ if property_field._type == 'many2one':
48+ model_obj = obj.pool.get(property_field._obj)
49+ left, operator, right = args[0]
50+ args1 = []
51+ if operator == '!=' and right == False:
52+ args1= [(1,'=',1)]
53+ elif operator == '=' and right == False and not default_val:
54+ ghost = True
55+ elif operator in ('ilike','not ilike','=','!='):
56+ args1= [(model_obj._rec_name,operator,right)]
57+ elif operator == 'in':
58+ args1= [('id',operator,right)]
59+ #/!\ By doing this I am forgetting the possible ghosts that could match
60+ model_ids = args1 and model_obj.search(cr,uid,args1,context=context) or []
61+ if model_ids:
62+ ghost = True if default_val and default_val.id in model_ids else False
63+ #/!\ This awful query has to be got rid, a better query should arise
64+ model_ids = map(lambda x:"'%s,%s'"%(model_obj._name,x),model_ids)
65+ model_ids = ",".join(model_ids)
66+ where_str += ' AND value_reference IN (%s)'%model_ids
67+ else:
68+ #/!\ Do not return anything in case that no arguments are passed
69+ #return [('id', '=', 0)]
70+ pass
71+
72+ elif property_field._type in ('date','datetime'):
73+ left, operator, right = args[0]
74+ args1 = []
75+ type_right = (type2field.get(property_field._type),right)
76+ if operator in ('=','!=','<=','<','>','>=','=?'):
77+ where_str += " AND %s = '%s'"%type_right%operator
78+ elif operator in ('=like' '=ilike', 'like', 'not like', 'ilike', 'not ilike'):
79+ #TODO: NotImplementedYet
80+ pass
81+ elif operator in ('in', 'not in', 'child_of'):
82+ #TODO: NotImplementedYet
83+ pass
84+
85+ elif property_field._type in ('float', 'boolean', 'integer'):
86+ left, operator, right = args[0]
87+ args1 = []
88+ type_right = (type2field.get(property_field._type),right)
89+ if operator in ('=','!=','<=','<','>','>=','=?'):
90+ where_str += " AND %s %%s %d"%type_right%operator
91+ elif operator in ('=like' '=ilike', 'like', 'not like', 'ilike', 'not ilike'):
92+ #TODO: NotImplementedYet
93+ pass
94+ elif operator in ('in', 'not in', 'child_of'):
95+ #TODO: NotImplementedYet
96+ pass
97+ elif property_field._type in ('char', 'text'):
98+ left, operator, right = args[0]
99+ args1 = []
100+ type_right = (type2field.get(property_field._type),right)
101+ if operator in ('=','!=','<=','<','>','>=','=?'):
102+ where_str += " AND %s = '%s'"%type_right%operator
103+ elif operator == '=like':
104+ where_str += " AND %s =like '%s%%'"%type_right
105+ elif operator == '=ilike':
106+ where_str += " AND %s =ilike '%s%%'"%type_right
107+ elif operator == 'like':
108+ where_str += " AND %s like '%s'"%type_right
109+ elif operator == 'not like':
110+ where_str += " AND %s not like '%s'"%type_right
111+ elif operator == 'ilike':
112+ where_str += " AND %s ilike '%s'"%type_right
113+ elif operator == 'not ilike':
114+ where_str += " AND %s not ilike '%s'"%type_right
115+ elif operator in ('in', 'not in', 'child_of'):
116+ #TODO: NotImplementedYet
117+ pass
118+ ghost_ids = []
119+ if ghost:
120+ # These are all the records from obj which actually have prop_name
121+ # set as a real property_field, the other records of obj just have
122+ # a 'ghost'
123+ query = "SELECT res_id FROM %s"%from_clause + where
124+ cr.execute(query)
125+ res = cr.fetchall()
126+ res = set(res)
127+ res = map(lambda x: int(x[1]), [x[0].split(',') for x in res])
128+
129+ #This ones are the ghosts
130+ ghost_ids = obj.search(cr,uid,[('id','not in',res)],context=context)
131+
132+ res = []
133+ if where_str:
134+ query = "SELECT res_id FROM %s"%from_clause + where + where_str
135+ cr.execute(query)
136+ res = cr.fetchall()
137+ res = set(res)
138+ res = map(lambda x: int(x[1]), [x[0].split(',') for x in res])
139+
140+ res += ghost_ids
141+ if not res:
142+ return [('id', '=', 0)]
143+ return [('id', 'in', res)]
144 # TODO: to rewrite more clean
145 def _fnct_write(self, obj, cr, uid, id, prop_name, id_val, obj_dest, context=None):
146 if context is None:
147@@ -1563,7 +1699,7 @@
148 if 'view_load' in args:
149 _logger.warning("view_load attribute is deprecated on ir.fields. Args: %r", args)
150 obj = 'relation' in args and args['relation'] or ''
151- function.__init__(self, self._fnct_read, False, self._fnct_write, obj=obj, multi='properties', **args)
152+ function.__init__(self, self._fnct_read, False, self._fnct_write, obj=obj, multi='properties', fnct_search=self._fnct_search, **args)
153
154 def restart(self):
155 self.field_id = {}