Merge lp:~akretion-team/openerp-product-attributes/openerp-product-attributes_limit_database_column_name into lp:~product-core-editors/openerp-product-attributes/7.0
- openerp-product-attributes_limit_database_column_name
- Merge into 7.0
Status: | Merged |
---|---|
Merged at revision: | 224 |
Proposed branch: | lp:~akretion-team/openerp-product-attributes/openerp-product-attributes_limit_database_column_name |
Merge into: | lp:~product-core-editors/openerp-product-attributes/7.0 |
Diff against target: |
459 lines (+180/-86) 2 files modified
base_custom_attributes/custom_attributes.py (+171/-82) base_custom_attributes/ir_model.py (+9/-4) |
To merge this branch: | bzr merge lp:~akretion-team/openerp-product-attributes/openerp-product-attributes_limit_database_column_name |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Guewen Baconnier @ Camptocamp | code review | Approve | |
Sébastien BEAU - http://www.akretion.com | Pending | ||
Quentin THEURET @Amaris | code review | Pending | |
Benoit Guillot - http://www.akretion.com | Pending | ||
Review via email: mp+194998@code.launchpad.net |
This proposal supersedes a proposal from 2013-09-27.
Commit message
Description of the change
[IMP] add a function to define allowed chars for database column name + cleaning code .py alignement
Benoit Guillot - http://www.akretion.com (benoit-guillot-z) wrote : Posted in a previous version of this proposal | # |
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : Posted in a previous version of this proposal | # |
Hi,
The next time, can you avoid to mix a cleaning and a fix?
Because we can't know where is your change and what it does without parsing and searching through all the diffs.
Can I propose a better name for the function "set_column_name"? "safe_column_name" maybe?
Thanks!
David BEAL (ak) (davidbeal) wrote : Posted in a previous version of this proposal | # |
Ok
Changes are done
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : Posted in a previous version of this proposal | # |
Thanks for the change!
Why not
re.sub(r'\W', '', string)
Instead of
filter((lambda x: re.search(
?
David BEAL (ak) (davidbeal) wrote : Posted in a previous version of this proposal | # |
attribute_code in magento doesn't support upper case
If you want to share attributes with openerp, magento and other plateforms you need to apply common rules with the more restrictif system
David BEAL (ak) (davidbeal) wrote : Posted in a previous version of this proposal | # |
Hi
Is it OK for everybody ?
Thanks for your response
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : Posted in a previous version of this proposal | # |
You apply lower() on the string just before the filter, so anyway you can't
have any uppercase chars, that's why I put \W. However, your regexp is more
explicit.
My remark was more on the usage of filter() which is inefficient vs
re.sub().
Thanks for the changes. Approve (I don't remember how to change my review
state from mail, I will change it afterwards from launchpad)
Le 2 oct. 2013 11:35, "David BEAL" <email address hidden> a écrit :
> attribute_code in magento doesn't support upper case
>
> If you want to share attributes with openerp, magento and other plateforms
> you need to apply common rules with the more restrictif system
> --
>
> https:/
> You are reviewing the proposed merge of
> lp:~akretion-team/openerp-product-attributes/openerp-product-attributes_limit_database_column_name
> into lp:openerp-product-attributes.
>
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) : Posted in a previous version of this proposal | # |
Quentin THEURET @Amaris (qtheuret) wrote : Posted in a previous version of this proposal | # |
LGTM
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : Posted in a previous version of this proposal | # |
The merge gives a conflict. Can you rebase on the latest revision please?
- 219. By David BEAL (ak)
-
[MERGE] merge again from main branch
- 220. By David BEAL (ak)
-
[FIX] extract 'sep' unused variable
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : | # |
LGTM
Preview Diff
1 | === modified file 'base_custom_attributes/custom_attributes.py' |
2 | --- base_custom_attributes/custom_attributes.py 2013-11-12 08:30:11 +0000 |
3 | +++ base_custom_attributes/custom_attributes.py 2013-11-13 08:38:32 +0000 |
4 | @@ -1,9 +1,9 @@ |
5 | # -*- encoding: utf-8 -*- |
6 | ############################################################################### |
7 | # # |
8 | -# base_attribute.attributes for OpenERP # |
9 | -# Copyright (C) 2011 Akretion Benoît GUILLOT <benoit.guillot@akretion.com> # |
10 | -# Copyright (C) 2013 Akretion Raphaël VALYI <raphael.valyi@akretion.com> # |
11 | +# base_attribute.attributes for OpenERP # |
12 | +# Copyright (C) 2011 Akretion Benoît GUILLOT <benoit.guillot@akretion.com> |
13 | +# Copyright (C) 2013 Akretion Raphaël VALYI <raphael.valyi@akretion.com> |
14 | # # |
15 | # This program is free software: you can redistribute it and/or modify # |
16 | # it under the terms of the GNU Affero General Public License as # |
17 | @@ -26,6 +26,15 @@ |
18 | from openerp.tools.translate import _ |
19 | from lxml import etree |
20 | from unidecode import unidecode # Debian package python-unidecode |
21 | +import re |
22 | + |
23 | + |
24 | +def safe_column_name(string): |
25 | + """This function prevent portability problem in database column name |
26 | + with other DBMS system |
27 | + Use case : if you synchronise attributes with other applications """ |
28 | + string = unidecode(string.replace(' ', '_').lower()) |
29 | + return re.sub(r'[^0-9a-z_]','', string) |
30 | |
31 | |
32 | class attribute_option(orm.Model): |
33 | @@ -40,15 +49,28 @@ |
34 | return [(r['model'], r['name']) for r in res] |
35 | |
36 | _columns = { |
37 | - 'name': fields.char('Name', size=128, translate=True, required=True), |
38 | - 'value_ref': fields.reference('Reference', selection=_get_model_list, size=128), |
39 | - 'attribute_id': fields.many2one('attribute.attribute', 'Product Attribute', required=True), |
40 | + 'name': fields.char( |
41 | + 'Name', |
42 | + size=128, |
43 | + translate=True, |
44 | + required=True), |
45 | + 'value_ref': fields.reference( |
46 | + 'Reference', |
47 | + selection=_get_model_list, |
48 | + size=128), |
49 | + 'attribute_id': fields.many2one( |
50 | + 'attribute.attribute', |
51 | + 'Product Attribute', |
52 | + required=True), |
53 | 'sequence': fields.integer('Sequence'), |
54 | } |
55 | |
56 | def name_change(self, cr, uid, ids, name, relation_model_id, context=None): |
57 | if relation_model_id: |
58 | - warning = {'title': _('Error!'), 'message': _("Use the 'Load Options' button instead to select appropriate model references.")} |
59 | + warning = {'title': _('Error!'), |
60 | + 'message': _("Use the 'Load Options' button " |
61 | + "instead to select appropriate " |
62 | + "model references'")} |
63 | return {"value": {"name": False}, "warning": warning} |
64 | else: |
65 | return True |
66 | @@ -59,11 +81,15 @@ |
67 | _rec_name = 'attribute_id' |
68 | |
69 | _columns = { |
70 | - 'attribute_id': fields.many2one('attribute.attribute', 'Attribute', required=True), |
71 | + 'attribute_id': fields.many2one( |
72 | + 'attribute.attribute', |
73 | + 'Product Attribute', |
74 | + required=True), |
75 | } |
76 | |
77 | _defaults = { |
78 | - 'attribute_id': lambda self, cr, uid, context: context.get('attribute_id', False) |
79 | + 'attribute_id': lambda self, cr, uid, context: |
80 | + context.get('attribute_id',False) |
81 | } |
82 | |
83 | def validate(self, cr, uid, ids, context=None): |
84 | @@ -86,12 +112,16 @@ |
85 | res = super(attribute_option_wizard, self).create(cr, uid, vals, context) |
86 | return res |
87 | |
88 | - def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): |
89 | - res = super(attribute_option_wizard, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu) |
90 | + def fields_view_get(self, cr, uid, view_id=None, view_type='form', |
91 | + context=None, toolbar=False, submenu=False): |
92 | + res = super(attribute_option_wizard, self).fields_view_get( |
93 | + cr, uid, view_id, view_type, context, toolbar, submenu) |
94 | if view_type == 'form' and context and context.get("attribute_id"): |
95 | attr_obj = self.pool.get("attribute.attribute") |
96 | - model_id = attr_obj.read(cr, uid, [context.get("attribute_id")], ['relation_model_id'])[0]['relation_model_id'][0] |
97 | - relation = self.pool.get("ir.model").read(cr, uid, [model_id], ["model"])[0]["model"] |
98 | + model_id = attr_obj.read(cr, uid, [context.get("attribute_id")], |
99 | + ['relation_model_id'])[0]['relation_model_id'][0] |
100 | + relation = self.pool.get("ir.model").read(cr, uid, [model_id], |
101 | + ["model"])[0]["model"] |
102 | res['fields'].update({'option_ids': { |
103 | 'domain': [], |
104 | 'string': "Options", |
105 | @@ -118,11 +148,10 @@ |
106 | kwargs = {'name': "%s" % attribute.name} |
107 | if attribute.ttype in ['many2many', 'text']: |
108 | parent = etree.SubElement(parent, 'group', colspan="2", col="4") |
109 | - sep = etree.SubElement(parent, |
110 | + etree.SubElement(parent, |
111 | 'separator', |
112 | string="%s" % attribute.field_description, |
113 | - colspan="4") |
114 | - |
115 | + colspan="4") |
116 | kwargs['nolabel'] = "1" |
117 | if attribute.ttype in ['many2one', 'many2many']: |
118 | if attribute.relation_model_id: |
119 | @@ -142,23 +171,30 @@ |
120 | kwargs['required'] = str(attribute.required or |
121 | attribute.required_on_views) |
122 | field = etree.SubElement(parent, 'field', **kwargs) |
123 | - orm.setup_modifiers(field, self.fields_get(cr, uid, attribute.name, context)) |
124 | + orm.setup_modifiers(field, self.fields_get(cr, uid, attribute.name, |
125 | + context)) |
126 | return parent |
127 | |
128 | - def _build_attributes_notebook(self, cr, uid, attribute_group_ids, context=None): |
129 | - notebook = etree.Element('notebook', name="attributes_notebook", colspan="4") |
130 | + def _build_attributes_notebook(self, cr, uid, attribute_group_ids, |
131 | + context=None): |
132 | + notebook = etree.Element('notebook', name="attributes_notebook", |
133 | + colspan="4") |
134 | toupdate_fields = [] |
135 | grp_obj = self.pool.get('attribute.group') |
136 | - for group in grp_obj.browse(cr, uid, attribute_group_ids, context=context): |
137 | - page = etree.SubElement(notebook, 'page', string=group.name.capitalize()) |
138 | + for group in grp_obj.browse(cr, uid, attribute_group_ids, |
139 | + context=context): |
140 | + page = etree.SubElement(notebook, 'page', |
141 | + string=group.name.capitalize()) |
142 | for attribute in group.attribute_ids: |
143 | if attribute.name not in toupdate_fields: |
144 | toupdate_fields.append(attribute.name) |
145 | - self._build_attribute_field(cr, uid, page, attribute, context=context) |
146 | + self._build_attribute_field(cr, uid, page, attribute, |
147 | + context=context) |
148 | return notebook, toupdate_fields |
149 | |
150 | - def relation_model_id_change(self, cr, uid, ids, relation_model_id, option_ids, context=None): |
151 | - "removed selected options as they would be inconsistent" |
152 | + def relation_model_id_change(self, cr, uid, ids, relation_model_id, |
153 | + option_ids, context=None): |
154 | + "removed selected options as they would be inconsistent" |
155 | return {'value': {'option_ids': [(2, i[1]) for i in option_ids]}} |
156 | |
157 | def button_add_options(self, cr, uid, ids, context=None): |
158 | @@ -173,24 +209,36 @@ |
159 | } |
160 | |
161 | _columns = { |
162 | - 'field_id': fields.many2one('ir.model.fields', 'Ir Model Fields', required=True, ondelete="cascade"), |
163 | - 'attribute_type': fields.selection([('char','Char'), |
164 | - ('text','Text'), |
165 | - ('select','Select'), |
166 | - ('multiselect','Multiselect'), |
167 | - ('boolean','Boolean'), |
168 | - ('integer','Integer'), |
169 | - ('date','Date'), |
170 | - ('datetime','Datetime'), |
171 | - ('binary','Binary'), |
172 | - ('float','Float')], |
173 | - 'Type', required=True), |
174 | - 'serialized': fields.boolean('Field serialized', |
175 | - help="If serialized, the field will be stocked in the serialized field: " |
176 | - "attribute_custom_tmpl or attribute_custom_variant depending on the field based_on"), |
177 | - 'option_ids': fields.one2many('attribute.option', 'attribute_id', 'Attribute Options'), |
178 | + 'field_id': fields.many2one( |
179 | + 'ir.model.fields', |
180 | + 'Ir Model Fields', |
181 | + required=True, |
182 | + ondelete="cascade"), |
183 | + 'attribute_type': fields.selection([ |
184 | + ('char', 'Char'), |
185 | + ('text', 'Text'), |
186 | + ('select', 'Select'), |
187 | + ('multiselect', 'Multiselect'), |
188 | + ('boolean', 'Boolean'), |
189 | + ('integer', 'Integer'), |
190 | + ('date', 'Date'), |
191 | + ('datetime', 'Datetime'), |
192 | + ('binary', 'Binary'), |
193 | + ('float', 'Float')], |
194 | + 'Type', required=True), |
195 | + 'serialized': fields.boolean( |
196 | + 'Field serialized', |
197 | + help="If serialized, the field will be stocked in the serialized " |
198 | + "field: attribute_custom_tmpl or attribute_custom_variant " |
199 | + "depending on the field based_on"), |
200 | + 'option_ids': fields.one2many( |
201 | + 'attribute.option', |
202 | + 'attribute_id', |
203 | + 'Attribute Options'), |
204 | 'create_date': fields.datetime('Created date', readonly=True), |
205 | - 'relation_model_id': fields.many2one('ir.model', 'Model'), |
206 | + 'relation_model_id': fields.many2one( |
207 | + 'ir.model', |
208 | + 'Model'), |
209 | 'required_on_views': fields.boolean( |
210 | 'Required (on views)', |
211 | help="If activated, the attribute will be mandatory on the views, " |
212 | @@ -199,11 +247,10 @@ |
213 | |
214 | def create(self, cr, uid, vals, context=None): |
215 | if vals.get('relation_model_id'): |
216 | - relation = self.pool.get('ir.model').read(cr, uid, |
217 | - [vals.get('relation_model_id')], ['model'])[0]['model'] |
218 | + relation = self.pool.get('ir.model').read( |
219 | + cr, uid, [vals.get('relation_model_id')], ['model'])[0]['model'] |
220 | else: |
221 | relation = 'attribute.option' |
222 | - |
223 | if vals['attribute_type'] == 'select': |
224 | vals['ttype'] = 'many2one' |
225 | vals['relation'] = relation |
226 | @@ -216,27 +263,31 @@ |
227 | |
228 | if vals.get('serialized'): |
229 | field_obj = self.pool.get('ir.model.fields') |
230 | - serialized_ids = field_obj.search(cr, uid, |
231 | - [('ttype', '=', 'serialized'), ('model_id', '=', vals['model_id']), |
232 | - ('name', '=', 'x_custom_json_attrs')], context=context) |
233 | + serialized_ids = field_obj.search(cr, uid, [ |
234 | + ('ttype', '=', 'serialized'), |
235 | + ('model_id', '=', vals['model_id']), |
236 | + ('name', '=', 'x_custom_json_attrs')], |
237 | + context=context) |
238 | if serialized_ids: |
239 | vals['serialization_field_id'] = serialized_ids[0] |
240 | else: |
241 | f_vals = { |
242 | 'name': u'x_custom_json_attrs', |
243 | - 'field_description': u'Serialized JSON Attributes', |
244 | + 'field_description': u'Serialized JSON Attributes', |
245 | 'ttype': 'serialized', |
246 | 'model_id': vals['model_id'], |
247 | } |
248 | - vals['serialization_field_id'] = field_obj.create(cr, uid, f_vals, {'manual': True}) |
249 | + vals['serialization_field_id'] = field_obj.create( |
250 | + cr, uid, f_vals, {'manual': True}) |
251 | vals['state'] = 'manual' |
252 | return super(attribute_attribute, self).create(cr, uid, vals, context) |
253 | |
254 | - def onchange_field_description(self, cr, uid, ids, field_description, name, create_date, context=None): |
255 | + def onchange_field_description(self, cr, uid, ids, field_description, |
256 | + name, create_date, context=None): |
257 | name = name or u'x_' |
258 | if field_description and not create_date: |
259 | - name = unidecode(u'x_%s' % field_description.replace(' ', '_').lower()) |
260 | - return {'value' : {'name' : name}} |
261 | + name = unicode('x_' + safe_column_name(field_description)) |
262 | + return {'value': {'name': name}} |
263 | |
264 | def onchange_name(self, cr, uid, ids, name, context=None): |
265 | res = {} |
266 | @@ -244,15 +295,15 @@ |
267 | name = u'x_%s' % name |
268 | else: |
269 | name = u'%s' % name |
270 | - res = {'value' : {'name' : unidecode(name)}} |
271 | + res = {'value': {'name': unidecode(name)}} |
272 | |
273 | #FILTER ON MODEL |
274 | - model_domain = [] |
275 | model_name = context.get('force_model') |
276 | if not model_name: |
277 | model_id = context.get('default_model_id') |
278 | if model_id: |
279 | - model = self.pool['ir.model'].browse(cr, uid, model_id, context=context) |
280 | + model = self.pool['ir.model'].browse(cr, uid, model_id, |
281 | + context=context) |
282 | model_name = model.model |
283 | if model_name: |
284 | model_obj = self.pool[model_name] |
285 | @@ -264,8 +315,8 @@ |
286 | def _get_default_model(self, cr, uid, context=None): |
287 | if context and context.get('force_model'): |
288 | model_id = self.pool['ir.model'].search(cr, uid, [ |
289 | - ['model', '=', context['force_model']] |
290 | - ], context=context) |
291 | + ('model', '=', context['force_model']) |
292 | + ], context=context) |
293 | if model_id: |
294 | return model_id[0] |
295 | return None |
296 | @@ -276,29 +327,42 @@ |
297 | |
298 | |
299 | class attribute_group(orm.Model): |
300 | - _name= "attribute.group" |
301 | + _name = "attribute.group" |
302 | _description = "Attribute Group" |
303 | - _order="sequence" |
304 | + _order ="sequence" |
305 | |
306 | _columns = { |
307 | - 'name': fields.char('Name', size=128, required=True, translate=True), |
308 | + 'name': fields.char( |
309 | + 'Name', |
310 | + size=128, |
311 | + required=True, |
312 | + translate=True), |
313 | 'sequence': fields.integer('Sequence'), |
314 | - 'attribute_set_id': fields.many2one('attribute.set', 'Attribute Set'), |
315 | - 'attribute_ids': fields.one2many('attribute.location', 'attribute_group_id', 'Attributes'), |
316 | - 'model_id': fields.many2one('ir.model', 'Model', required=True), |
317 | + 'attribute_set_id': fields.many2one( |
318 | + 'attribute.set', |
319 | + 'Attribute Set'), |
320 | + 'attribute_ids': fields.one2many( |
321 | + 'attribute.location', |
322 | + 'attribute_group_id', |
323 | + 'Attributes'), |
324 | + 'model_id': fields.many2one( |
325 | + 'ir.model', |
326 | + 'Model', |
327 | + required=True), |
328 | } |
329 | |
330 | def create(self, cr, uid, vals, context=None): |
331 | - for attribute in vals.get('attribute_ids', []): |
332 | - if vals.get('attribute_set_id') and attribute[2] and not attribute[2].get('attribute_set_id'): |
333 | + for attribute in vals['attribute_ids']: |
334 | + if vals.get('attribute_set_id') and attribute[2] and \ |
335 | + not attribute[2].get('attribute_set_id'): |
336 | attribute[2]['attribute_set_id'] = vals['attribute_set_id'] |
337 | return super(attribute_group, self).create(cr, uid, vals, context) |
338 | |
339 | def _get_default_model(self, cr, uid, context=None): |
340 | if context and context.get('force_model'): |
341 | - model_id = self.pool['ir.model'].search(cr, uid, [ |
342 | - ['model', '=', context['force_model']] |
343 | - ], context=context) |
344 | + model_id = self.pool['ir.model'].search( |
345 | + cr, uid, [['model', '=', context['force_model']]], |
346 | + context=context) |
347 | if model_id: |
348 | return model_id[0] |
349 | return None |
350 | @@ -312,16 +376,26 @@ |
351 | _name = "attribute.set" |
352 | _description = "Attribute Set" |
353 | _columns = { |
354 | - 'name': fields.char('Name', size=128, required=True, translate=True), |
355 | - 'attribute_group_ids': fields.one2many('attribute.group', 'attribute_set_id', 'Attribute Groups'), |
356 | - 'model_id': fields.many2one('ir.model', 'Model', required=True), |
357 | + 'name': fields.char( |
358 | + 'Name', |
359 | + size=128, |
360 | + required=True, |
361 | + translate=True), |
362 | + 'attribute_group_ids': fields.one2many( |
363 | + 'attribute.group', |
364 | + 'attribute_set_id', |
365 | + 'Attribute Groups'), |
366 | + 'model_id': fields.many2one( |
367 | + 'ir.model', |
368 | + 'Model', |
369 | + required=True), |
370 | } |
371 | |
372 | def _get_default_model(self, cr, uid, context=None): |
373 | if context and context.get('force_model'): |
374 | - model_id = self.pool['ir.model'].search(cr, uid, [ |
375 | - ['model', '=', context['force_model']] |
376 | - ], context=context) |
377 | + model_id = self.pool['ir.model'].search( |
378 | + cr, uid, [['model', '=', context['force_model']]], |
379 | + context=context) |
380 | if model_id: |
381 | return model_id[0] |
382 | return None |
383 | @@ -330,22 +404,37 @@ |
384 | 'model_id': _get_default_model |
385 | } |
386 | |
387 | + |
388 | class attribute_location(orm.Model): |
389 | _name = "attribute.location" |
390 | _description = "Attribute Location" |
391 | _order="sequence" |
392 | _inherits = {'attribute.attribute': 'attribute_id'} |
393 | |
394 | - |
395 | def _get_attribute_loc_from_group(self, cr, uid, ids, context=None): |
396 | - return self.pool.get('attribute.location').search(cr, uid, [('attribute_group_id', 'in', ids)], context=context) |
397 | + return self.pool.get('attribute.location').search( |
398 | + cr, uid, [('attribute_group_id', 'in', ids)], context=context) |
399 | |
400 | _columns = { |
401 | - 'attribute_id': fields.many2one('attribute.attribute', 'Attribute', required=True, ondelete="cascade"), |
402 | - 'attribute_set_id': fields.related('attribute_group_id', 'attribute_set_id', type='many2one', relation='attribute.set', string='Attribute Set', readonly=True, |
403 | -store={ |
404 | - 'attribute.group': (_get_attribute_loc_from_group, ['attribute_set_id'], 10), |
405 | - }), |
406 | - 'attribute_group_id': fields.many2one('attribute.group', 'Attribute Group', required=True), |
407 | + 'attribute_id': fields.many2one( |
408 | + 'attribute.attribute', |
409 | + 'Product Attribute', |
410 | + required=True, |
411 | + ondelete="cascade"), |
412 | + 'attribute_set_id': fields.related( |
413 | + 'attribute_group_id', |
414 | + 'attribute_set_id', |
415 | + type='many2one', |
416 | + relation='attribute.set', |
417 | + string='Attribute Set', |
418 | + readonly=True, |
419 | + store={ |
420 | + 'attribute.group': (_get_attribute_loc_from_group, |
421 | + ['attribute_set_id'], 10), |
422 | + }), |
423 | + 'attribute_group_id': fields.many2one( |
424 | + 'attribute.group', |
425 | + 'Attribute Group', |
426 | + required=True), |
427 | 'sequence': fields.integer('Sequence'), |
428 | } |
429 | |
430 | === modified file 'base_custom_attributes/ir_model.py' |
431 | --- base_custom_attributes/ir_model.py 2012-08-21 14:10:21 +0000 |
432 | +++ base_custom_attributes/ir_model.py 2013-11-13 08:38:32 +0000 |
433 | @@ -1,8 +1,8 @@ |
434 | # -*- encoding: utf-8 -*- |
435 | ############################################################################### |
436 | # # |
437 | -# product_custom_attributes for OpenERP # |
438 | -# Copyright (C) 2011 Akretion Benoît GUILLOT <benoit.guillot@akretion.com> # |
439 | +# product_custom_attributes for OpenERP |
440 | +# Copyright (C) 2011 Akretion Benoît GUILLOT <benoit.guillot@akretion.com> |
441 | # # |
442 | # This program is free software: you can redistribute it and/or modify # |
443 | # it under the terms of the GNU Affero General Public License as # |
444 | @@ -27,8 +27,13 @@ |
445 | |
446 | _inherit = "ir.model.fields" |
447 | _columns = { |
448 | - 'field_description': fields.char('Field Label', required=True, size=256, translate=True), |
449 | + 'field_description': fields.char( |
450 | + 'Field Label', |
451 | + required=True, |
452 | + size=256, |
453 | + translate=True), |
454 | } |
455 | _sql_constraints = [ |
456 | - ('name_model_uniq', 'unique (name, model_id)', 'The name of the field has to be uniq for a given model !'), |
457 | + ('name_model_uniq', 'unique (name, model_id)', |
458 | + 'The name of the field has to be uniq for a given model !'), |
459 | ] |
LGTM,
code review, no test