~xrg/openobject-doc/trunk-xrg

« back to all changes in this revision

Viewing changes to 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
Type of Fields
 
2
==============
 
3
 
 
4
Basic Types
 
5
------------
 
6
 
 
7
:boolean:
 
8
 
 
9
A boolean (true, false).
 
10
 
 
11
        Syntax::
 
12
 
 
13
                fields.boolean('Field Name' [, Optional Parameters]),
 
14
 
 
15
:integer:
 
16
 
 
17
An integer.
 
18
 
 
19
        Syntax::
 
20
 
 
21
                fields.integer('Field Name' [, Optional Parameters]),
 
22
 
 
23
:float:
 
24
 
 
25
A floating point number.
 
26
 
 
27
        Syntax::
 
28
 
 
29
                fields.float('Field Name' [, Optional Parameters]),
 
30
 
 
31
        .. note::
 
32
 
 
33
                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.
 
34
 
 
35
 
 
36
        Example
 
37
 
 
38
        'rate' : fields.float('Relative Change rate', digits=(12,6) [, Optional Parameters]),
 
39
 
 
40
:char:
 
41
 
 
42
A string of limited length. The required size parameter determines its size.
 
43
 
 
44
        Syntax::
 
45
 
 
46
                fields.char('Field Name', size=n [, Optional Parameters]), # where ''n'' is an integer.
 
47
 
 
48
Example
 
49
 
 
50
'city' : fields.char('City Name', size=30, required=True),
 
51
 
 
52
:text:
 
53
 
 
54
A text field with no limit in length.
 
55
 
 
56
        Syntax::
 
57
 
 
58
                fields.text('Field Name' [, Optional Parameters]),
 
59
 
 
60
:date:
 
61
 
 
62
A date.
 
63
 
 
64
        Syntax::
 
65
 
 
66
                fields.date('Field Name' [, Optional Parameters]),
 
67
 
 
68
:datetime:
 
69
 
 
70
Allows to store a date and the time of day in the same field.
 
71
 
 
72
        Syntax::
 
73
 
 
74
                fields.datetime('Field Name' [, Optional Parameters]),
 
75
 
 
76
:binary:
 
77
 
 
78
A binary chain
 
79
 
 
80
:selection:
 
81
 
 
82
A field which allows the user to make a selection between various predefined values.
 
83
 
 
84
        Syntax::
 
85
 
 
86
                fields.selection((('n','Unconfirmed'), ('c','Confirmed')),
 
87
                                   'Field Name' [, Optional Parameters]),
 
88
 
 
89
.. note::
 
90
 
 
91
        Format of the selection parameter: tuple of tuples of strings of the form::
 
92
 
 
93
                (('key_or_value', 'string_to_display'), ... )
 
94
 
 
95
*Example*
 
96
 
 
97
Using relation fields **many2one** with **selection**. In fields definitions add::
 
98
 
 
99
        ...,
 
100
        'my_field': fields.many2one('mymodule.relation.model', 'Title', selection=_sel_func),
 
101
        ...,
 
102
 
 
103
And then define the _sel_func like this (but before the fields definitions)::
 
104
 
 
105
        def _sel_func(self, cr, uid, context={}):
 
106
            obj = self.pool.get('mymodule.relation.model')
 
107
            ids = obj.search(cr, uid, [])
 
108
            res = obj.read(cr, uid, ids, ['name', 'id'], context)
 
109
            res = [(r['id'], r['name']) for r in res]
 
110
            return res
 
111
 
 
112
 
 
113
Relational Types
 
114
----------------
 
115
 
 
116
:one2one:
 
117
 
 
118
A one2one field expresses a one:to:one relation between two objects. It is deprecated. Use many2one instead.
 
119
 
 
120
        syntax::
 
121
 
 
122
                fields.one2one('other.object.name', 'Field Name')
 
123
 
 
124
:many2one:
 
125
 
 
126
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
 
127
 
 
128
        syntax::
 
129
 
 
130
                fields.many2one('other.object.name', 'Field Name', optional parameter)
 
131
 
 
132
        * Optional parameters:
 
133
                - ondelete: What should happen when the resource this field points to is deleted.
 
134
                        + Predefined value: "cascade", "set null"
 
135
                        + Default value: "set null"
 
136
                - required: True
 
137
                - readonly: True
 
138
                - select: True - (creates an index on the Foreign Key field)
 
139
 
 
140
        *Example*
 
141
 
 
142
                'commercial': fields.many2one('res.users', 'Commercial', ondelete='cascade'),
 
143
 
 
144
:one2many:
 
145
 
 
146
TODO
 
147
 
 
148
        syntax::
 
149
 
 
150
                fields.one2many('other.object.name', 'Field relation id', 'Fieldname', optional parameter)
 
151
 
 
152
        * Optional parameters:
 
153
                - invisible: True/False
 
154
                - states: ?
 
155
                - readonly: True/False
 
156
 
 
157
        *Example*
 
158
 
 
159
                'address': fields.one2many('res.partner.address', 'partner_id', 'Contacts'),
 
160
 
 
161
:many2many:
 
162
 
 
163
TODO
 
164
 
 
165
        syntax::
 
166
 
 
167
                fields.many2many('other.object.name',
 
168
                                 'relation object',
 
169
                                 'other.object.id',
 
170
                                 'actual.object.id',
 
171
                                 'Field Name')
 
172
 
 
173
        * where
 
174
                - other.object.name is the other object which belongs to the relation
 
175
                - relation object is the table that makes the link
 
176
                - other.object.id and actual.object.id are the fields' names used in the relation table
 
177
 
 
178
        Example::
 
179
 
 
180
                'category_id':
 
181
                   fields.many2many(
 
182
                    'res.partner.category',
 
183
                    'res_partner_category_rel',
 
184
                    'partner_id',
 
185
                    'category_id',
 
186
                    'Categories'),
 
187
 
 
188
        To make it bidirectionnal (= create a field in the other object)::
 
189
 
 
190
                class other_object_name2(osv.osv):
 
191
                    _inherit = 'other.object.name'
 
192
                    _columns = {
 
193
                        'other_field': fields.many2many('actual.object.name', 'relation object', 'actual.object.id', 'other.object.id', 'Other Field Name'),
 
194
                    }
 
195
                other_object_name2()
 
196
 
 
197
        Example::
 
198
 
 
199
                class res_partner_category2(osv.osv):
 
200
                    _inherit = 'res.partner.category'
 
201
                    _columns = {
 
202
                        'partner_id': fields.many2many('res.partner', 'res_partner_category_rel', 'category_id', 'partner_id', 'Partners'),
 
203
                    }
 
204
                res_partner_category2()
 
205
 
 
206
 
 
207
:related:
 
208
 
 
209
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::
 
210
 
 
211
        'country_id': fields.related('state_id', 'country_id', type="many2one",
 
212
                      relation="module.country", string="Country", store=False)
 
213
 
 
214
Functional Field
 
215
++++++++++++++++
 
216
 
 
217
A functional field is a field whose value is calculated by a function (rather than being stored in the database).
 
218
 
 
219
**Parameters:** fnct, arg=None, fnct_inv=None, fnct_inv_arg=None, type="%green%float%black%", fnct_search=None, obj=None, method=False, store=True
 
220
 
 
221
where
 
222
 
 
223
    * :guilabel:`type` is the field type name returned by the function. It can be any field type name except function.
 
224
    * :guilabel:`store` If you want to store field in database or not. Default is False.
 
225
    * :guilabel:`method` whether the field is computed by a method (of an object) or a global function
 
226
    * :guilabel:`fnct` is the function or method that will compute the field value. It must have been declared before declaring the functional field.
 
227
 
 
228
If *method* is True, the signature of the method must be::
 
229
 
 
230
    def fnct(self, cr, uid, ids, field_name, arg, context)
 
231
 
 
232
otherwise (if it is a global function), its signature must be::
 
233
 
 
234
    def fnct(cr, table, ids, field_name, arg, context)
 
235
 
 
236
Either way, it must return a dictionary of values of the form **{id'_1_': value'_1_', id'_2_': value'_2_',...}.**
 
237
 
 
238
The values of the returned dictionary must be of the type specified by the type argument in the field declaration.
 
239
 
 
240
    * :guilabel:`fnct_inv` is the function or method that will allow writing values in that field.
 
241
 
 
242
If *method* is true, the signature of the method must be::
 
243
 
 
244
    def fnct(self, cr, uid, ids, field_name, field_value, arg, context)
 
245
 
 
246
otherwise (if it is a global function), it should be::
 
247
 
 
248
    def fnct(cr, table, ids, field_name, field_value, arg, context)
 
249
 
 
250
* :guilabel:`fnct_search` allows you to define the searching behaviour on that field.
 
251
 
 
252
If method is true, the signature of the method must be::
 
253
 
 
254
    def fnct(self, cr, uid, obj, name, args)
 
255
 
 
256
otherwise (if it is a global function), it should be::
 
257
 
 
258
    def fnct(cr, uid, obj, name, args)
 
259
 
 
260
The return value is a list countaining 3-part tuplets which are used in search funtion::
 
261
 
 
262
    return [('id','in',[1,3,5])]
 
263
 
 
264
:Example Of Functional Field:
 
265
 
 
266
Suppose we create a contract object which is :
 
267
 
 
268
.. code-block:: python
 
269
 
 
270
    class hr_contract(osv.osv):
 
271
        _name = 'hr.contract'
 
272
        _description = 'Contract'
 
273
        _columns = {
 
274
        'name' : fields.char('Contract Name', size=30, required=True),
 
275
        'employee_id' : fields.many2one('hr.employee', 'Employee', required=True),
 
276
        'function' : fields.many2one('res.partner.function', 'Function'),
 
277
        }
 
278
    hr_contract()
 
279
 
 
280
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:
 
281
 
 
282
.. code-block:: python
 
283
 
 
284
    class hr_employee(osv.osv):
 
285
        _name = "hr.employee"
 
286
        _description = "Employee"
 
287
        _inherit = "hr.employee"
 
288
        _columns = {
 
289
        'contract_ids' : fields.one2many('hr.contract', 'employee_id', 'Contracts'),
 
290
        'function' : fields.function(_get_cur_function_id, type='many2one', obj="res.partner.function",
 
291
                                     method=True, string='Contract Function'),
 
292
        }
 
293
    hr_employee()
 
294
 
 
295
.. note:: three points
 
296
 
 
297
        * :guilabel:`type` ='many2one' is because the function field must create a many2one field; function is declared as a many2one in hr_contract also.
 
298
        * :guilabel:`obj` ="res.partner.function" is used to specify that the object to use for the many2one field is res.partner.function.
 
299
        * 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:
 
300
 
 
301
.. code-block:: python
 
302
 
 
303
    def _get_cur_function_id(self, cr, uid, ids, field_name, arg, context):
 
304
        for i in ids:
 
305
        #get the id of the current function of the employee of identifier "i"
 
306
        sql_req= """
 
307
        SELECT f.id AS func_id
 
308
        FROM hr_contract c
 
309
          LEFT JOIN res_partner_function f ON (f.id = c.function)
 
310
        WHERE
 
311
          (c.employee_id = %d)
 
312
        """ % (i,)
 
313
 
 
314
        cr.execute(sql_req)
 
315
        sql_res = cr.dictfetchone()
 
316
 
 
317
        if sql_res: #The employee has one associated contract
 
318
            res[i] = sql_res['func_id']
 
319
        else:
 
320
            #res[i] must be set to False and not to None because of XML:RPC
 
321
            # "cannot marshal None unless allow_none is enabled"
 
322
            res[i] = False
 
323
            return res
 
324
 
 
325
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.
 
326
 
 
327
:store={...} Enhancement:
 
328
 
 
329
It will compute the field depends on other objects.
 
330
 
 
331
:Syntax: 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.
 
332
 
 
333
:Example In membership module:
 
334
 
 
335
.. code-block:: python
 
336
 
 
337
    'membership_state': fields.function(_membership_state, method=True, string='Current membership state', type='selection', selection=STATE,
 
338
      store={'account.invoice':(_get_invoice_partner,['state'], 10),
 
339
      'membership.membership_line':(_get_partner_id,['state'], 10),
 
340
      'res.partner':(lambda self,cr,uid,ids,c={}:ids, ['free_member'], 10)}),
 
341
 
 
342
Property Fields
 
343
+++++++++++++++
 
344
 
 
345
.. describe:: Declaring a property
 
346
 
 
347
A property is a special field: fields.property.
 
348
 
 
349
.. code-block:: python
 
350
 
 
351
        class res_partner(osv.osv):
 
352
            _name = "res.partner"
 
353
            _inherit = "res.partner"
 
354
            _columns = {
 
355
                        'property_product_pricelist': fields.property(
 
356
                        'product.pricelist',
 
357
                        type='many2one',·
 
358
                        relation='product.pricelist',·
 
359
                        string="Sale Pricelist",·
 
360
                        method=True,
 
361
                        view_load=True,
 
362
                        group_name="Pricelists Properties"),
 
363
            }
 
364
 
 
365
 
 
366
Then you have to create the default value in a .XML file for this property:
 
367
 
 
368
.. code-block:: xml
 
369
 
 
370
        <record model="ir.property" id="property_product_pricelist">
 
371
            <field name="name">property_product_pricelist</field>
 
372
            <field name="fields_id" search="[('model','=','res.partner'),
 
373
              ('name','=','property_product_pricelist')]"/>
 
374
            <field name="value" eval="'product.pricelist,'+str(list0)"/>
 
375
        </record>
 
376
 
 
377
..
 
378
 
 
379
.. tip::
 
380
 
 
381
        if the default value points to a resource from another module, you can use the ref function like this:
 
382
 
 
383
        <field name="value" eval="'product.pricelist,'+str(ref('module.data_id'))"/>
 
384
 
 
385
**Putting properties in forms**
 
386
 
 
387
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).
 
388
 
 
389
Properties are displayed by section, depending on the group_name attribute. (It is rendered in the client like a separator tag).
 
390
 
 
391
**How does this work ?**
 
392
 
 
393
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.
 
394
 
 
395
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.
 
396
 
 
397
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.
 
398
 
 
399
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.
 
400
 
 
401
**Using properties or normal fields**
 
402
 
 
403
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.
 
404
 
 
405
 
 
406
Here are a few tips to help you choose between a normal field or a property:
 
407
 
 
408
Normal fields extend the object, adding more features or data.
 
409
 
 
410
A property is a concept that is attached to an object and have special features:
 
411
 
 
412
* Different value for the same property depending on the company
 
413
* Rights management per field
 
414
* It's a link between resources (many2one)
 
415
 
 
416
**Example 1: Account Receivable**
 
417
 
 
418
The default "Account Receivable" for a specific partner is implemented as a property because:
 
419
 
 
420
    * 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.
 
421
 
 
422
    * 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.
 
423
 
 
424
    * The default account receivable is the same for all partners and is configured from the general property menu (in administration).
 
425
 
 
426
.. note::
 
427
        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.)
 
428
 
 
429
**Example 2: Product Times**
 
430
 
 
431
The product expiry module implements all delays related to products: removal date, product usetime, ... This module is very useful for food industries.
 
432
 
 
433
This module inherits from the product.product object and adds new fields to it:
 
434
 
 
435
.. code-block:: python
 
436
 
 
437
        class product_product(osv.osv):
 
438
 
 
439
            _inherit = 'product.product'
 
440
            _name = 'product.product'
 
441
            _columns = {
 
442
 
 
443
                'life_time': fields.integer('Product lifetime'),
 
444
                'use_time': fields.integer('Product usetime'),
 
445
                'removal_time': fields.integer('Product removal time'),
 
446
                'alert_time': fields.integer('Product alert time'),
 
447
                }
 
448
 
 
449
        product_product()
 
450
 
 
451
..
 
452
 
 
453
This module adds simple fields to the product.product object. We did not use properties because:
 
454
 
 
455
    * We extend a product, the life_time field is a concept related to a product, not to another object.
 
456
    * We do not need a right management per field, the different delays are managed by the same people that manage all products.
 
457