~xrg/openobject-doc/trunk-xrg

« back to all changes in this revision

Viewing changes to i18n/uk/source/developer/2_5_Objects_Fields_Methods/field_type.rst

  • Committer: TruongSinh Tran
  • Date: 2009-07-17 18:59:45 UTC
  • Revision ID: truongsinh@vipescoserver-20090717185945-ajjp3zso6xh5jddm
[FIX]private issue

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
.. i18n: Type of Fields
 
3
.. i18n: ==============
 
4
 
 
5
Type of Fields
 
6
==============
 
7
 
 
8
.. i18n: Basic Types
 
9
.. i18n: ------------
 
10
 
 
11
Basic Types
 
12
------------
 
13
 
 
14
.. i18n: :boolean:
 
15
 
 
16
:boolean:
 
17
 
 
18
.. i18n: A boolean (true, false).
 
19
 
 
20
A boolean (true, false).
 
21
 
 
22
.. i18n:         Syntax::
 
23
.. i18n: 
 
24
.. i18n:                 fields.boolean('Field Name' [, Optional Parameters]),
 
25
 
 
26
        Syntax::
 
27
 
 
28
                fields.boolean('Field Name' [, Optional Parameters]),
 
29
 
 
30
.. i18n: :integer:
 
31
 
 
32
:integer:
 
33
 
 
34
.. i18n: An integer.
 
35
.. i18n:         
 
36
.. i18n:         Syntax::
 
37
.. i18n: 
 
38
.. i18n:                 fields.integer('Field Name' [, Optional Parameters]),
 
39
 
 
40
An integer.
 
41
        
 
42
        Syntax::
 
43
 
 
44
                fields.integer('Field Name' [, Optional Parameters]),
 
45
 
 
46
.. i18n: :float:
 
47
 
 
48
:float:
 
49
 
 
50
.. i18n: A floating point number.
 
51
 
 
52
A floating point number.
 
53
 
 
54
.. i18n:         Syntax::
 
55
.. i18n: 
 
56
.. i18n:                 fields.float('Field Name' [, Optional Parameters]),
 
57
 
 
58
        Syntax::
 
59
 
 
60
                fields.float('Field Name' [, Optional Parameters]),
 
61
 
 
62
.. i18n:         .. note::
 
63
.. i18n: 
 
64
.. i18n:                 The optional parameter digits defines the precision and scale of the number. The scale being the number of digits after the decimal point whereas the precision is the total number of significant digits in the number (before and after the decimal point). If the parameter digits is not present, the number will be a double precision floating point number. Warning: these floating-point numbers are inexact (not any value can be converted to its binary representation) and this can lead to rounding errors. You should always use the digits parameter for monetary amounts.
 
65
.. i18n:         
 
66
.. i18n:         
 
67
.. i18n:         Example
 
68
.. i18n: 
 
69
.. i18n:         'rate' : fields.float('Relative Change rate', digits=(12,6) [, Optional Parameters]),
 
70
 
 
71
        .. note::
 
72
 
 
73
                The optional parameter digits defines the precision and scale of the number. The scale being the number of digits after the decimal point whereas the precision is the total number of significant digits in the number (before and after the decimal point). If the parameter digits is not present, the number will be a double precision floating point number. Warning: these floating-point numbers are inexact (not any value can be converted to its binary representation) and this can lead to rounding errors. You should always use the digits parameter for monetary amounts.
 
74
        
 
75
        
 
76
        Example
 
77
 
 
78
        'rate' : fields.float('Relative Change rate', digits=(12,6) [, Optional Parameters]),
 
79
 
 
80
.. i18n: :char:
 
81
 
 
82
:char:
 
83
 
 
84
.. i18n: A string of limited length. The required size parameter determines its size.
 
85
 
 
86
A string of limited length. The required size parameter determines its size.
 
87
 
 
88
.. i18n:         Syntax::
 
89
.. i18n: 
 
90
.. i18n:                 fields.char('Field Name', size=n [, Optional Parameters]), # where ''n'' is an integer.
 
91
 
 
92
        Syntax::
 
93
 
 
94
                fields.char('Field Name', size=n [, Optional Parameters]), # where ''n'' is an integer.
 
95
 
 
96
.. i18n: Example
 
97
 
 
98
Example
 
99
 
 
100
.. i18n: 'city' : fields.char('City Name', size=30, required=True),
 
101
 
 
102
'city' : fields.char('City Name', size=30, required=True),
 
103
 
 
104
.. i18n: :text:
 
105
 
 
106
:text:
 
107
 
 
108
.. i18n: A text field with no limit in length.
 
109
 
 
110
A text field with no limit in length.
 
111
 
 
112
.. i18n:         Syntax::
 
113
.. i18n: 
 
114
.. i18n:                 fields.text('Field Name' [, Optional Parameters]),
 
115
 
 
116
        Syntax::
 
117
 
 
118
                fields.text('Field Name' [, Optional Parameters]),
 
119
 
 
120
.. i18n: :date:
 
121
 
 
122
:date:
 
123
 
 
124
.. i18n: A date.
 
125
 
 
126
A date.
 
127
 
 
128
.. i18n:         Syntax::
 
129
.. i18n: 
 
130
.. i18n:                 fields.date('Field Name' [, Optional Parameters]),
 
131
 
 
132
        Syntax::
 
133
 
 
134
                fields.date('Field Name' [, Optional Parameters]),
 
135
 
 
136
.. i18n: :datetime:
 
137
 
 
138
:datetime:
 
139
 
 
140
.. i18n: Allows to store a date and the time of day in the same field.
 
141
 
 
142
Allows to store a date and the time of day in the same field.
 
143
 
 
144
.. i18n:         Syntax::
 
145
.. i18n: 
 
146
.. i18n:                 fields.datetime('Field Name' [, Optional Parameters]),
 
147
 
 
148
        Syntax::
 
149
 
 
150
                fields.datetime('Field Name' [, Optional Parameters]),
 
151
 
 
152
.. i18n: :binary:
 
153
 
 
154
:binary:
 
155
 
 
156
.. i18n: A binary chain
 
157
 
 
158
A binary chain
 
159
 
 
160
.. i18n: :selection:
 
161
 
 
162
:selection:
 
163
 
 
164
.. i18n: A field which allows the user to make a selection between various predefined values.
 
165
 
 
166
A field which allows the user to make a selection between various predefined values.
 
167
 
 
168
.. i18n:         Syntax::
 
169
.. i18n: 
 
170
.. i18n:                 fields.selection((('n','Unconfirmed'), ('c','Confirmed')), 
 
171
.. i18n:                                    'Field Name' [, Optional Parameters]),
 
172
 
 
173
        Syntax::
 
174
 
 
175
                fields.selection((('n','Unconfirmed'), ('c','Confirmed')), 
 
176
                                   'Field Name' [, Optional Parameters]),
 
177
 
 
178
.. i18n: .. note::
 
179
.. i18n: 
 
180
.. i18n:         Format of the selection parameter: tuple of tuples of strings of the form::
 
181
.. i18n: 
 
182
.. i18n:                 (('key_or_value', 'string_to_display'), ... )
 
183
 
 
184
.. note::
 
185
 
 
186
        Format of the selection parameter: tuple of tuples of strings of the form::
 
187
 
 
188
                (('key_or_value', 'string_to_display'), ... )
 
189
 
 
190
.. i18n: *Example*
 
191
 
 
192
*Example*
 
193
 
 
194
.. i18n: Using relation fields **many2one** with **selection**. In fields definitions add::
 
195
.. i18n: 
 
196
.. i18n:         ...,
 
197
.. i18n:         'my_field': fields.many2one('mymodule.relation.model', 'Title', selection=_sel_func), 
 
198
.. i18n:         ...,
 
199
 
 
200
Using relation fields **many2one** with **selection**. In fields definitions add::
 
201
 
 
202
        ...,
 
203
        'my_field': fields.many2one('mymodule.relation.model', 'Title', selection=_sel_func), 
 
204
        ...,
 
205
 
 
206
.. i18n: And then define the _sel_func like this (but before the fields definitions)::
 
207
.. i18n: 
 
208
.. i18n:         def _sel_func(self, cr, uid, context={}): 
 
209
.. i18n:             obj = self.pool.get('mymodule.relation.model') 
 
210
.. i18n:             ids = obj.search(cr, uid, []) 
 
211
.. i18n:             res = obj.read(cr, uid, ids, ['name', 'id'], context) 
 
212
.. i18n:             res = [(r['id'], r['name']) for r in res] 
 
213
.. i18n:             return res
 
214
.. i18n:             
 
215
 
 
216
And then define the _sel_func like this (but before the fields definitions)::
 
217
 
 
218
        def _sel_func(self, cr, uid, context={}): 
 
219
            obj = self.pool.get('mymodule.relation.model') 
 
220
            ids = obj.search(cr, uid, []) 
 
221
            res = obj.read(cr, uid, ids, ['name', 'id'], context) 
 
222
            res = [(r['id'], r['name']) for r in res] 
 
223
            return res
 
224
            
 
225
 
 
226
.. i18n: Relational Types
 
227
.. i18n: ----------------
 
228
 
 
229
Relational Types
 
230
----------------
 
231
 
 
232
.. i18n: :one2one:
 
233
 
 
234
:one2one:
 
235
 
 
236
.. i18n: A one2one field expresses a one:to:one relation between two objects. It is deprecated. Use many2one instead.
 
237
.. i18n:         
 
238
.. i18n:         syntax::
 
239
.. i18n: 
 
240
.. i18n:                 fields.one2one('other.object.name', 'Field Name')
 
241
 
 
242
A one2one field expresses a one:to:one relation between two objects. It is deprecated. Use many2one instead.
 
243
        
 
244
        syntax::
 
245
 
 
246
                fields.one2one('other.object.name', 'Field Name')
 
247
 
 
248
.. i18n: :many2one:
 
249
 
 
250
:many2one:
 
251
 
 
252
.. i18n: Associates this object to a parent object via this Field. For example Department an Employee belongs to would Many to one. i.e Many employees will belong to a Department
 
253
 
 
254
Associates this object to a parent object via this Field. For example Department an Employee belongs to would Many to one. i.e Many employees will belong to a Department
 
255
 
 
256
.. i18n:         syntax::
 
257
.. i18n: 
 
258
.. i18n:                 fields.many2one('other.object.name', 'Field Name', optional parameter)
 
259
 
 
260
        syntax::
 
261
 
 
262
                fields.many2one('other.object.name', 'Field Name', optional parameter)
 
263
 
 
264
.. i18n:         * Optional parameters:
 
265
.. i18n:                 - ondelete: What should happen when the resource this field points to is deleted.
 
266
.. i18n:                         + Predefined value: "cascade", "set null"
 
267
.. i18n:                         + Default value: "set null" 
 
268
.. i18n:                 - required: True
 
269
.. i18n:                 - readonly: True
 
270
.. i18n:                 - select: True - (creates an index on the Foreign Key field) 
 
271
 
 
272
        * Optional parameters:
 
273
                - ondelete: What should happen when the resource this field points to is deleted.
 
274
                        + Predefined value: "cascade", "set null"
 
275
                        + Default value: "set null" 
 
276
                - required: True
 
277
                - readonly: True
 
278
                - select: True - (creates an index on the Foreign Key field) 
 
279
 
 
280
.. i18n:         *Example*
 
281
 
 
282
        *Example*
 
283
 
 
284
.. i18n:                 'commercial': fields.many2one('res.users', 'Commercial', ondelete='cascade'),
 
285
 
 
286
                'commercial': fields.many2one('res.users', 'Commercial', ondelete='cascade'),
 
287
 
 
288
.. i18n: :one2many:
 
289
 
 
290
:one2many:
 
291
 
 
292
.. i18n: TODO
 
293
 
 
294
TODO
 
295
 
 
296
.. i18n:         syntax::
 
297
.. i18n: 
 
298
.. i18n:                 fields.one2many('other.object.name', 'Field relation id', 'Fieldname', optional parameter)
 
299
 
 
300
        syntax::
 
301
 
 
302
                fields.one2many('other.object.name', 'Field relation id', 'Fieldname', optional parameter)
 
303
 
 
304
.. i18n:         * Optional parameters:
 
305
.. i18n:                 - invisible: True/False
 
306
.. i18n:                 - states: ?
 
307
.. i18n:                 - readonly: True/False 
 
308
 
 
309
        * Optional parameters:
 
310
                - invisible: True/False
 
311
                - states: ?
 
312
                - readonly: True/False 
 
313
 
 
314
.. i18n:         *Example*
 
315
 
 
316
        *Example*
 
317
 
 
318
.. i18n:                 'address': fields.one2many('res.partner.address', 'partner_id', 'Contacts'),
 
319
 
 
320
                'address': fields.one2many('res.partner.address', 'partner_id', 'Contacts'),
 
321
 
 
322
.. i18n: :many2many:
 
323
 
 
324
:many2many:
 
325
 
 
326
.. i18n: TODO
 
327
 
 
328
TODO
 
329
 
 
330
.. i18n:         syntax::
 
331
.. i18n: 
 
332
.. i18n:                 fields.many2many('other.object.name', 
 
333
.. i18n:                                  'relation object', 
 
334
.. i18n:                                  'other.object.id', 
 
335
.. i18n:                                  'actual.object.id', 
 
336
.. i18n:                                  'Field Name')
 
337
 
 
338
        syntax::
 
339
 
 
340
                fields.many2many('other.object.name', 
 
341
                                 'relation object', 
 
342
                                 'other.object.id', 
 
343
                                 'actual.object.id', 
 
344
                                 'Field Name')
 
345
 
 
346
.. i18n:         * where
 
347
.. i18n:                 - other.object.name is the other object which belongs to the relation
 
348
.. i18n:                 - relation object is the table that makes the link
 
349
.. i18n:                 - other.object.id and actual.object.id are the fields' names used in the relation table 
 
350
 
 
351
        * where
 
352
                - other.object.name is the other object which belongs to the relation
 
353
                - relation object is the table that makes the link
 
354
                - other.object.id and actual.object.id are the fields' names used in the relation table 
 
355
 
 
356
.. i18n:         Example::
 
357
.. i18n: 
 
358
.. i18n:                 'category_id': 
 
359
.. i18n:                    fields.many2many(
 
360
.. i18n:                     'res.partner.category', 
 
361
.. i18n:                     'res_partner_category_rel', 
 
362
.. i18n:                     'partner_id', 
 
363
.. i18n:                     'category_id', 
 
364
.. i18n:                     'Categories'),
 
365
 
 
366
        Example::
 
367
 
 
368
                'category_id': 
 
369
                   fields.many2many(
 
370
                    'res.partner.category', 
 
371
                    'res_partner_category_rel', 
 
372
                    'partner_id', 
 
373
                    'category_id', 
 
374
                    'Categories'),
 
375
 
 
376
.. i18n: :related:
 
377
 
 
378
:related:
 
379
 
 
380
.. i18n: Sometimes you need to refer the relation of a relation. For example, supposing you have objects: City <- State <- Country, and you need to refer Country in a City, you can define a field as below in the City object::
 
381
.. i18n: 
 
382
.. i18n:         'country_id': fields.related('state_id', 'country_id', type="many2one", 
 
383
.. i18n:                                      relation="module.country", string="Country", store=False)
 
384
 
 
385
Sometimes you need to refer the relation of a relation. For example, supposing you have objects: City <- State <- Country, and you need to refer Country in a City, you can define a field as below in the City object::
 
386
 
 
387
        'country_id': fields.related('state_id', 'country_id', type="many2one", 
 
388
                                      relation="module.country", string="Country", store=False)
 
389
 
 
390
.. i18n: Functional Field
 
391
.. i18n: ++++++++++++++++
 
392
 
 
393
Functional Field
 
394
++++++++++++++++
 
395
 
 
396
.. i18n: A functional field is a field whose value is calculated by a function (rather than being stored in the database).
 
397
 
 
398
A functional field is a field whose value is calculated by a function (rather than being stored in the database).
 
399
 
 
400
.. i18n: **Parameters:** fnct, arg=None, fnct_inv=None, fnct_inv_arg=None, type="%green%float%black%", fnct_search=None, obj=None, method=False, store=True
 
401
 
 
402
**Parameters:** fnct, arg=None, fnct_inv=None, fnct_inv_arg=None, type="%green%float%black%", fnct_search=None, obj=None, method=False, store=True
 
403
 
 
404
.. i18n: where
 
405
 
 
406
where
 
407
 
 
408
.. i18n:     * :guilabel:`type` is the field type name returned by the function. It can be any field type name except function.
 
409
.. i18n:     * :guilabel:`store` If you want to store field in database or not. Default is False.
 
410
.. i18n:     * :guilabel:`method` whether the field is computed by a method (of an object) or a global function
 
411
.. i18n:     * :guilabel:`fnct` is the function or method that will compute the field value. It must have been declared before declaring the functional field. 
 
412
 
 
413
    * :guilabel:`type` is the field type name returned by the function. It can be any field type name except function.
 
414
    * :guilabel:`store` If you want to store field in database or not. Default is False.
 
415
    * :guilabel:`method` whether the field is computed by a method (of an object) or a global function
 
416
    * :guilabel:`fnct` is the function or method that will compute the field value. It must have been declared before declaring the functional field. 
 
417
 
 
418
.. i18n: If *method* is True, the signature of the method must be::
 
419
.. i18n: 
 
420
.. i18n:        def fnct(self, cr, uid, ids, field_name, arg, context)
 
421
 
 
422
If *method* is True, the signature of the method must be::
 
423
 
 
424
        def fnct(self, cr, uid, ids, field_name, arg, context)
 
425
 
 
426
.. i18n: otherwise (if it is a global function), its signature must be::
 
427
.. i18n: 
 
428
.. i18n:        def fnct(cr, table, ids, field_name, arg, context)
 
429
 
 
430
otherwise (if it is a global function), its signature must be::
 
431
 
 
432
        def fnct(cr, table, ids, field_name, arg, context)
 
433
 
 
434
.. i18n: Either way, it must return a dictionary of values of the form **{id'_1_': value'_1_', id'_2_': value'_2_',...}.**
 
435
 
 
436
Either way, it must return a dictionary of values of the form **{id'_1_': value'_1_', id'_2_': value'_2_',...}.**
 
437
 
 
438
.. i18n: The values of the returned dictionary must be of the type specified by the type argument in the field declaration.
 
439
 
 
440
The values of the returned dictionary must be of the type specified by the type argument in the field declaration.
 
441
 
 
442
.. i18n:     * :guilabel:`fnct_inv` is the function or method that will allow writing values in that field. 
 
443
 
 
444
    * :guilabel:`fnct_inv` is the function or method that will allow writing values in that field. 
 
445
 
 
446
.. i18n: If *method* is true, the signature of the method must be::
 
447
.. i18n: 
 
448
.. i18n:        def fnct(self, cr, uid, ids, field_name, field_value, arg, context)
 
449
 
 
450
If *method* is true, the signature of the method must be::
 
451
 
 
452
        def fnct(self, cr, uid, ids, field_name, field_value, arg, context)
 
453
 
 
454
.. i18n: otherwise (if it is a global function), it should be::
 
455
.. i18n: 
 
456
.. i18n:        def fnct(cr, table, ids, field_name, field_value, arg, context)
 
457
 
 
458
otherwise (if it is a global function), it should be::
 
459
 
 
460
        def fnct(cr, table, ids, field_name, field_value, arg, context)
 
461
 
 
462
.. i18n: * :guilabel:`fnct_search` allows you to define the searching behaviour on that field. 
 
463
 
 
464
* :guilabel:`fnct_search` allows you to define the searching behaviour on that field. 
 
465
 
 
466
.. i18n: If method is true, the signature of the method must be::
 
467
.. i18n: 
 
468
.. i18n:        def fnct(self, cr, uid, obj, name, args)
 
469
 
 
470
If method is true, the signature of the method must be::
 
471
 
 
472
        def fnct(self, cr, uid, obj, name, args)
 
473
 
 
474
.. i18n: otherwise (if it is a global function), it should be::
 
475
.. i18n: 
 
476
.. i18n:        def fnct(cr, uid, obj, name, args)
 
477
 
 
478
otherwise (if it is a global function), it should be::
 
479
 
 
480
        def fnct(cr, uid, obj, name, args)
 
481
 
 
482
.. i18n: The return value is a list countaining 3-part tuplets which are used in search funtion::
 
483
.. i18n: 
 
484
.. i18n:        return [('id','in',[1,3,5])]
 
485
 
 
486
The return value is a list countaining 3-part tuplets which are used in search funtion::
 
487
 
 
488
        return [('id','in',[1,3,5])]
 
489
 
 
490
.. i18n: :Example Of Functional Field:
 
491
 
 
492
:Example Of Functional Field:
 
493
 
 
494
.. i18n: Suppose we create a contract object which is :
 
495
 
 
496
Suppose we create a contract object which is :
 
497
 
 
498
.. i18n: .. code-block:: python
 
499
.. i18n: 
 
500
.. i18n:        class hr_contract(osv.osv):
 
501
.. i18n:            _name = 'hr.contract'
 
502
.. i18n:            _description = 'Contract'
 
503
.. i18n:            _columns = {
 
504
.. i18n:                'name' : fields.char('Contract Name', size=30, required=True),
 
505
.. i18n:                'employee_id' : fields.many2one('hr.employee', 'Employee', required=True),
 
506
.. i18n:                'function' : fields.many2one('res.partner.function', 'Function'),
 
507
.. i18n:            }
 
508
.. i18n:        hr_contract()
 
509
 
 
510
.. code-block:: python
 
511
 
 
512
        class hr_contract(osv.osv):
 
513
            _name = 'hr.contract'
 
514
            _description = 'Contract'
 
515
            _columns = {
 
516
                'name' : fields.char('Contract Name', size=30, required=True),
 
517
                'employee_id' : fields.many2one('hr.employee', 'Employee', required=True),
 
518
                'function' : fields.many2one('res.partner.function', 'Function'),
 
519
            }
 
520
        hr_contract()
 
521
 
 
522
.. i18n: If we want to add a field that retrieves the function of an employee by looking its current contract, we use a functional field. The object hr_employee is inherited this way:
 
523
 
 
524
If we want to add a field that retrieves the function of an employee by looking its current contract, we use a functional field. The object hr_employee is inherited this way:
 
525
 
 
526
.. i18n: .. code-block:: python
 
527
.. i18n: 
 
528
.. i18n:        class hr_employee(osv.osv):
 
529
.. i18n:            _name = "hr.employee"
 
530
.. i18n:            _description = "Employee"
 
531
.. i18n:            _inherit = "hr.employee"
 
532
.. i18n:            _columns = {
 
533
.. i18n:                'contract_ids' : fields.one2many('hr.contract', 'employee_id', 'Contracts'),
 
534
.. i18n:                'function' : fields.function(_get_cur_function_id, type='many2one', obj="res.partner.function",
 
535
.. i18n:                                             method=True, string='Contract Function'),
 
536
.. i18n:            }
 
537
.. i18n:        hr_employee()
 
538
 
 
539
.. code-block:: python
 
540
 
 
541
        class hr_employee(osv.osv):
 
542
            _name = "hr.employee"
 
543
            _description = "Employee"
 
544
            _inherit = "hr.employee"
 
545
            _columns = {
 
546
                'contract_ids' : fields.one2many('hr.contract', 'employee_id', 'Contracts'),
 
547
                'function' : fields.function(_get_cur_function_id, type='many2one', obj="res.partner.function",
 
548
                                             method=True, string='Contract Function'),
 
549
            }
 
550
        hr_employee()
 
551
 
 
552
.. i18n: .. note:: three points
 
553
.. i18n: 
 
554
.. i18n:            * :guilabel:`type` ='many2one' is because the function field must create a many2one field; function is declared as a many2one in hr_contract also.
 
555
.. i18n:            * :guilabel:`obj` ="res.partner.function" is used to specify that the object to use for the many2one field is res.partner.function.
 
556
.. i18n:            * We called our method :guilabel:`_get_cur_function_id` because its role is to return a dictionary whose keys are ids of employees, and whose corresponding values are ids of the function of those employees. The code of this method is: 
 
557
 
 
558
.. note:: three points
 
559
 
 
560
            * :guilabel:`type` ='many2one' is because the function field must create a many2one field; function is declared as a many2one in hr_contract also.
 
561
            * :guilabel:`obj` ="res.partner.function" is used to specify that the object to use for the many2one field is res.partner.function.
 
562
            * We called our method :guilabel:`_get_cur_function_id` because its role is to return a dictionary whose keys are ids of employees, and whose corresponding values are ids of the function of those employees. The code of this method is: 
 
563
 
 
564
.. i18n: .. code-block:: python
 
565
.. i18n: 
 
566
.. i18n:        def _get_cur_function_id(self, cr, uid, ids, field_name, arg, context):
 
567
.. i18n:            for i in ids:
 
568
.. i18n:                #get the id of the current function of the employee of identifier "i"
 
569
.. i18n:                sql_req= """
 
570
.. i18n:                SELECT f.id AS func_id
 
571
.. i18n:                FROM hr_contract c
 
572
.. i18n:                  LEFT JOIN res_partner_function f ON (f.id = c.function)
 
573
.. i18n:                WHERE
 
574
.. i18n:                  (c.employee_id = %d)
 
575
.. i18n:                """ % (i,)
 
576
.. i18n:         
 
577
.. i18n:                cr.execute(sql_req)
 
578
.. i18n:                sql_res = cr.dictfetchone()
 
579
.. i18n:         
 
580
.. i18n:                if sql_res: #The employee has one associated contract
 
581
.. i18n:                    res[i] = sql_res['func_id']
 
582
.. i18n:                else:
 
583
.. i18n:                    #res[i] must be set to False and not to None because of XML:RPC
 
584
.. i18n:                    # "cannot marshal None unless allow_none is enabled"
 
585
.. i18n:                    res[i] = False
 
586
.. i18n:                    return res
 
587
 
 
588
.. code-block:: python
 
589
 
 
590
        def _get_cur_function_id(self, cr, uid, ids, field_name, arg, context):
 
591
            for i in ids:
 
592
                #get the id of the current function of the employee of identifier "i"
 
593
                sql_req= """
 
594
                SELECT f.id AS func_id
 
595
                FROM hr_contract c
 
596
                  LEFT JOIN res_partner_function f ON (f.id = c.function)
 
597
                WHERE
 
598
                  (c.employee_id = %d)
 
599
                """ % (i,)
 
600
         
 
601
                cr.execute(sql_req)
 
602
                sql_res = cr.dictfetchone()
 
603
         
 
604
                if sql_res: #The employee has one associated contract
 
605
                    res[i] = sql_res['func_id']
 
606
                else:
 
607
                    #res[i] must be set to False and not to None because of XML:RPC
 
608
                    # "cannot marshal None unless allow_none is enabled"
 
609
                    res[i] = False
 
610
                    return res
 
611
 
 
612
.. i18n: The id of the function is retrieved using a SQL query. Note that if the query returns no result, the value of sql_res['func_id'] will be None. We force the False value in this case value because XML:RPC (communication between the server and the client) doesn't allow to transmit this value.
 
613
 
 
614
The id of the function is retrieved using a SQL query. Note that if the query returns no result, the value of sql_res['func_id'] will be None. We force the False value in this case value because XML:RPC (communication between the server and the client) doesn't allow to transmit this value.
 
615
 
 
616
.. i18n: :store={...} Enhancement:
 
617
 
 
618
:store={...} Enhancement:
 
619
 
 
620
.. i18n: It will compute the field depends on other objects.
 
621
 
 
622
It will compute the field depends on other objects.
 
623
 
 
624
.. i18n: :Syntex: store={'object_name':(function_name,['field_name1','field_name2'],priority)} It will call function function_name when any changes will be applied on field list ['field1','field2'] on object 'object_name' and output of the function will send as a parameter for main function of the field.
 
625
 
 
626
:Syntex: store={'object_name':(function_name,['field_name1','field_name2'],priority)} It will call function function_name when any changes will be applied on field list ['field1','field2'] on object 'object_name' and output of the function will send as a parameter for main function of the field.
 
627
 
 
628
.. i18n: :Example In membership module:
 
629
 
 
630
:Example In membership module:
 
631
 
 
632
.. i18n: .. code-block:: python
 
633
.. i18n: 
 
634
.. i18n:        'membership_state': fields.function(_membership_state, method=True, string='Current membership state', type='selection', selection=STATE, 
 
635
.. i18n:          store={'account.invoice':(_get_invoice_partner,['state'], 10),
 
636
.. i18n:          'membership.membership_line':(_get_partner_id,['state'], 10),
 
637
.. i18n:          'res.partner':(lambda self,cr,uid,ids,c={}:ids, ['free_member'], 10)}),
 
638
 
 
639
.. code-block:: python
 
640
 
 
641
        'membership_state': fields.function(_membership_state, method=True, string='Current membership state', type='selection', selection=STATE, 
 
642
          store={'account.invoice':(_get_invoice_partner,['state'], 10),
 
643
          'membership.membership_line':(_get_partner_id,['state'], 10),
 
644
          'res.partner':(lambda self,cr,uid,ids,c={}:ids, ['free_member'], 10)}),
 
645
 
 
646
.. i18n: Property Fields
 
647
.. i18n: +++++++++++++++
 
648
 
 
649
Property Fields
 
650
+++++++++++++++
 
651
 
 
652
.. i18n: .. describe:: Declaring a property
 
653
 
 
654
.. describe:: Declaring a property
 
655
 
 
656
.. i18n: A property is a special field: fields.property.
 
657
 
 
658
A property is a special field: fields.property.
 
659
 
 
660
.. i18n: .. code-block:: python
 
661
.. i18n: 
 
662
.. i18n:         class res_partner(osv.osv):
 
663
.. i18n:             _name = "res.partner"
 
664
.. i18n:             _inherit = "res.partner"
 
665
.. i18n:             _columns = {
 
666
.. i18n:                         'property_product_pricelist': fields.property( 
 
667
.. i18n:                         'product.pricelist', 
 
668
.. i18n:                         type='many2one',· 
 
669
.. i18n:                         relation='product.pricelist',· 
 
670
.. i18n:                         string="Sale Pricelist",· 
 
671
.. i18n:                         method=True, 
 
672
.. i18n:                         view_load=True, 
 
673
.. i18n:                         group_name="Pricelists Properties"), 
 
674
.. i18n:             }
 
675
 
 
676
.. code-block:: python
 
677
 
 
678
        class res_partner(osv.osv):
 
679
            _name = "res.partner"
 
680
            _inherit = "res.partner"
 
681
            _columns = {
 
682
                        'property_product_pricelist': fields.property( 
 
683
                        'product.pricelist', 
 
684
                        type='many2one',· 
 
685
                        relation='product.pricelist',· 
 
686
                        string="Sale Pricelist",· 
 
687
                        method=True, 
 
688
                        view_load=True, 
 
689
                        group_name="Pricelists Properties"), 
 
690
            }
 
691
 
 
692
.. i18n: Then you have to create the default value in a .XML file for this property:
 
693
 
 
694
Then you have to create the default value in a .XML file for this property:
 
695
 
 
696
.. i18n: .. code-block:: xml
 
697
.. i18n: 
 
698
.. i18n:         <record model="ir.property" id="property_product_pricelist">
 
699
.. i18n:             <field name="name">property_product_pricelist</field> 
 
700
.. i18n:             <field name="fields_id" search="[('model','=','res.partner'),
 
701
.. i18n:               ('name','=','property_product_pricelist')]"/> 
 
702
.. i18n:             <field name="value" eval="'product.pricelist,'+str(list0)"/> 
 
703
.. i18n:         </record>
 
704
 
 
705
.. code-block:: xml
 
706
 
 
707
        <record model="ir.property" id="property_product_pricelist">
 
708
            <field name="name">property_product_pricelist</field> 
 
709
            <field name="fields_id" search="[('model','=','res.partner'),
 
710
              ('name','=','property_product_pricelist')]"/> 
 
711
            <field name="value" eval="'product.pricelist,'+str(list0)"/> 
 
712
        </record>
 
713
 
 
714
.. i18n: ..
 
715
 
 
716
..
 
717
 
 
718
.. i18n: .. tip:: 
 
719
.. i18n:         
 
720
.. i18n:         if the default value points to a resource from another module, you can use the ref function like this:
 
721
.. i18n:         
 
722
.. i18n:         <field name="value" eval="'product.pricelist,'+str(ref('module.data_id'))"/> 
 
723
 
 
724
.. tip:: 
 
725
        
 
726
        if the default value points to a resource from another module, you can use the ref function like this:
 
727
        
 
728
        <field name="value" eval="'product.pricelist,'+str(ref('module.data_id'))"/> 
 
729
 
 
730
.. i18n: **Putting properties in forms**
 
731
 
 
732
**Putting properties in forms**
 
733
 
 
734
.. i18n: To add properties in forms, just put the <properties/> tag in your form. This will automatically add all properties fields that are related to this object. The system will add properties depending on your rights. (some people will be able to change a specific property, others won't).
 
735
 
 
736
To add properties in forms, just put the <properties/> tag in your form. This will automatically add all properties fields that are related to this object. The system will add properties depending on your rights. (some people will be able to change a specific property, others won't).
 
737
 
 
738
.. i18n: Properties are displayed by section, depending on the group_name attribute. (It is rendered in the client like a separator tag).
 
739
 
 
740
Properties are displayed by section, depending on the group_name attribute. (It is rendered in the client like a separator tag).
 
741
 
 
742
.. i18n: **How does this work ?**
 
743
 
 
744
**How does this work ?**
 
745
 
 
746
.. i18n: The fields.property class inherits from fields.function and overrides the read and write method. The type of this field is many2one, so in the form a property is represented like a many2one function.
 
747
 
 
748
The fields.property class inherits from fields.function and overrides the read and write method. The type of this field is many2one, so in the form a property is represented like a many2one function.
 
749
 
 
750
.. i18n: But the value of a property is stored in the ir.property class/table as a complete record. The stored value is a field of type reference (not many2one) because each property may point to a different object. If you edit properties values (from the administration menu), these are represented like a field of type reference.
 
751
 
 
752
But the value of a property is stored in the ir.property class/table as a complete record. The stored value is a field of type reference (not many2one) because each property may point to a different object. If you edit properties values (from the administration menu), these are represented like a field of type reference.
 
753
 
 
754
.. i18n: When you read a property, the program gives you the property attached to the instance of object you are reading. It this object has no value, the system will give you the default property.
 
755
 
 
756
When you read a property, the program gives you the property attached to the instance of object you are reading. It this object has no value, the system will give you the default property.
 
757
 
 
758
.. i18n: The definition of a property is stored in the ir.model.fields class like any other fields. In the definition of the property, you can add groups that are allowed to change to property.
 
759
 
 
760
The definition of a property is stored in the ir.model.fields class like any other fields. In the definition of the property, you can add groups that are allowed to change to property.
 
761
 
 
762
.. i18n: **Using properties or normal fields**
 
763
 
 
764
**Using properties or normal fields**
 
765
 
 
766
.. i18n: When you want to add a new feature, you will have to choose to implement it as a property or as normal field. Use a normal field when you inherit from an object and want to extend this object. Use a property when the new feature is not related to the object but to an external concept.
 
767
 
 
768
When you want to add a new feature, you will have to choose to implement it as a property or as normal field. Use a normal field when you inherit from an object and want to extend this object. Use a property when the new feature is not related to the object but to an external concept.
 
769
 
 
770
.. i18n: Here are a few tips to help you choose between a normal field or a property:
 
771
 
 
772
Here are a few tips to help you choose between a normal field or a property:
 
773
 
 
774
.. i18n: Normal fields extend the object, adding more features or data.
 
775
 
 
776
Normal fields extend the object, adding more features or data.
 
777
 
 
778
.. i18n: A property is a concept that is attached to an object and have special features:
 
779
 
 
780
A property is a concept that is attached to an object and have special features:
 
781
 
 
782
.. i18n: * Different value for the same property depending on the company
 
783
.. i18n: * Rights management per field
 
784
.. i18n: * It's a link between resources (many2one) 
 
785
 
 
786
* Different value for the same property depending on the company
 
787
* Rights management per field
 
788
* It's a link between resources (many2one) 
 
789
 
 
790
.. i18n: **Example 1: Account Receivable**
 
791
 
 
792
**Example 1: Account Receivable**
 
793
 
 
794
.. i18n: The default "Account Receivable" for a specific partner is implemented as a property because:
 
795
 
 
796
The default "Account Receivable" for a specific partner is implemented as a property because:
 
797
 
 
798
.. i18n:     * This is a concept related to the account chart and not to the partner, so it is an account property that is visible on a partner form. Rights have to be managed on this fields for accountants, these are not the same rights that are applied to partner objects. So you have specific rights just for this field of the partner form: only accountants may change the account receivable of a partner. 
 
799
.. i18n: 
 
800
.. i18n:     * This is a multi-company field: the same partner may have different account receivable values depending on the company the user belongs to. In a multi-company system, there is one account chart per company. The account receivable of a partner depends on the company it placed the sale order. 
 
801
.. i18n: 
 
802
.. i18n:     * The default account receivable is the same for all partners and is configured from the general property menu (in administration). 
 
803
 
 
804
    * This is a concept related to the account chart and not to the partner, so it is an account property that is visible on a partner form. Rights have to be managed on this fields for accountants, these are not the same rights that are applied to partner objects. So you have specific rights just for this field of the partner form: only accountants may change the account receivable of a partner. 
 
805
 
 
806
    * This is a multi-company field: the same partner may have different account receivable values depending on the company the user belongs to. In a multi-company system, there is one account chart per company. The account receivable of a partner depends on the company it placed the sale order. 
 
807
 
 
808
    * The default account receivable is the same for all partners and is configured from the general property menu (in administration). 
 
809
 
 
810
.. i18n: .. note::
 
811
.. i18n:         One interesting thing is that properties avoid "spaghetti" code. The account module depends on the partner (base) module. But you can install the partner (base) module without the accounting module. If you add a field that points to an account in the partner object, both objects will depend on each other. It's much more difficult to maintain and code (for instance, try to remove a table when both tables are pointing to each others.)
 
812
 
 
813
.. note::
 
814
        One interesting thing is that properties avoid "spaghetti" code. The account module depends on the partner (base) module. But you can install the partner (base) module without the accounting module. If you add a field that points to an account in the partner object, both objects will depend on each other. It's much more difficult to maintain and code (for instance, try to remove a table when both tables are pointing to each others.)
 
815
 
 
816
.. i18n: **Example 2: Product Times**
 
817
 
 
818
**Example 2: Product Times**
 
819
 
 
820
.. i18n: The product expiry module implements all delays related to products: removal date, product usetime, ... This module is very useful for food industries.
 
821
 
 
822
The product expiry module implements all delays related to products: removal date, product usetime, ... This module is very useful for food industries.
 
823
 
 
824
.. i18n: This module inherits from the product.product object and adds new fields to it:
 
825
 
 
826
This module inherits from the product.product object and adds new fields to it:
 
827
 
 
828
.. i18n: .. code-block:: python
 
829
.. i18n: 
 
830
.. i18n:         class product_product(osv.osv):
 
831
.. i18n: 
 
832
.. i18n:             _inherit = 'product.product' 
 
833
.. i18n:             _name = 'product.product' 
 
834
.. i18n:             _columns = {
 
835
.. i18n: 
 
836
.. i18n:                 'life_time': fields.integer('Product lifetime'), 
 
837
.. i18n:                 'use_time': fields.integer('Product usetime'), 
 
838
.. i18n:                 'removal_time': fields.integer('Product removal time'), 
 
839
.. i18n:                 'alert_time': fields.integer('Product alert time'), 
 
840
.. i18n:                 } 
 
841
.. i18n: 
 
842
.. i18n:         product_product()
 
843
 
 
844
.. code-block:: python
 
845
 
 
846
        class product_product(osv.osv):
 
847
 
 
848
            _inherit = 'product.product' 
 
849
            _name = 'product.product' 
 
850
            _columns = {
 
851
 
 
852
                'life_time': fields.integer('Product lifetime'), 
 
853
                'use_time': fields.integer('Product usetime'), 
 
854
                'removal_time': fields.integer('Product removal time'), 
 
855
                'alert_time': fields.integer('Product alert time'), 
 
856
                } 
 
857
 
 
858
        product_product()
 
859
 
 
860
.. i18n: ..
 
861
 
 
862
..
 
863
 
 
864
.. i18n: This module adds simple fields to the product.product object. We did not use properties because:
 
865
 
 
866
This module adds simple fields to the product.product object. We did not use properties because:
 
867
 
 
868
.. i18n:     * We extend a product, the life_time field is a concept related to a product, not to another object.
 
869
.. i18n:     * We do not need a right management per field, the different delays are managed by the same people that manage all products. 
 
870
 
 
871
    * We extend a product, the life_time field is a concept related to a product, not to another object.
 
872
    * We do not need a right management per field, the different delays are managed by the same people that manage all products.