9
A boolean (true, false).
13
fields.boolean('Field Name' [, Optional Parameters]),
21
fields.integer('Field Name' [, Optional Parameters]),
25
A floating point number.
29
fields.float('Field Name' [, Optional Parameters]),
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.
38
'rate' : fields.float('Relative Change rate', digits=(12,6) [, Optional Parameters]),
42
A string of limited length. The required size parameter determines its size.
46
fields.char('Field Name', size=n [, Optional Parameters]), # where ''n'' is an integer.
50
'city' : fields.char('City Name', size=30, required=True),
54
A text field with no limit in length.
58
fields.text('Field Name' [, Optional Parameters]),
66
fields.date('Field Name' [, Optional Parameters]),
70
Allows to store a date and the time of day in the same field.
74
fields.datetime('Field Name' [, Optional Parameters]),
82
A field which allows the user to make a selection between various predefined values.
86
fields.selection((('n','Unconfirmed'), ('c','Confirmed')),
87
'Field Name' [, Optional Parameters]),
91
Format of the selection parameter: tuple of tuples of strings of the form::
93
(('key_or_value', 'string_to_display'), ... )
97
Using relation fields **many2one** with **selection**. In fields definitions add::
100
'my_field': fields.many2one('mymodule.relation.model', 'Title', selection=_sel_func),
103
And then define the _sel_func like this (but before the fields definitions)::
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]
118
A one2one field expresses a one:to:one relation between two objects. It is deprecated. Use many2one instead.
122
fields.one2one('other.object.name', 'Field Name')
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
130
fields.many2one('other.object.name', 'Field Name', optional parameter)
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"
138
- select: True - (creates an index on the Foreign Key field)
142
'commercial': fields.many2one('res.users', 'Commercial', ondelete='cascade'),
150
fields.one2many('other.object.name', 'Field relation id', 'Fieldname', optional parameter)
152
* Optional parameters:
153
- invisible: True/False
155
- readonly: True/False
159
'address': fields.one2many('res.partner.address', 'partner_id', 'Contacts'),
167
fields.many2many('other.object.name',
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
182
'res.partner.category',
183
'res_partner_category_rel',
188
To make it bidirectionnal (= create a field in the other object)::
190
class other_object_name2(osv.osv):
191
_inherit = 'other.object.name'
193
'other_field': fields.many2many('actual.object.name', 'relation object', 'actual.object.id', 'other.object.id', 'Other Field Name'),
199
class res_partner_category2(osv.osv):
200
_inherit = 'res.partner.category'
202
'partner_id': fields.many2many('res.partner', 'res_partner_category_rel', 'category_id', 'partner_id', 'Partners'),
204
res_partner_category2()
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::
211
'country_id': fields.related('state_id', 'country_id', type="many2one",
212
relation="module.country", string="Country", store=False)
217
A functional field is a field whose value is calculated by a function (rather than being stored in the database).
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
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.
228
If *method* is True, the signature of the method must be::
230
def fnct(self, cr, uid, ids, field_name, arg, context)
232
otherwise (if it is a global function), its signature must be::
234
def fnct(cr, table, ids, field_name, arg, context)
236
Either way, it must return a dictionary of values of the form **{id'_1_': value'_1_', id'_2_': value'_2_',...}.**
238
The values of the returned dictionary must be of the type specified by the type argument in the field declaration.
240
* :guilabel:`fnct_inv` is the function or method that will allow writing values in that field.
242
If *method* is true, the signature of the method must be::
244
def fnct(self, cr, uid, ids, field_name, field_value, arg, context)
246
otherwise (if it is a global function), it should be::
248
def fnct(cr, table, ids, field_name, field_value, arg, context)
250
* :guilabel:`fnct_search` allows you to define the searching behaviour on that field.
252
If method is true, the signature of the method must be::
254
def fnct(self, cr, uid, obj, name, args)
256
otherwise (if it is a global function), it should be::
258
def fnct(cr, uid, obj, name, args)
260
The return value is a list countaining 3-part tuplets which are used in search funtion::
262
return [('id','in',[1,3,5])]
264
:Example Of Functional Field:
266
Suppose we create a contract object which is :
268
.. code-block:: python
270
class hr_contract(osv.osv):
271
_name = 'hr.contract'
272
_description = 'Contract'
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'),
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:
282
.. code-block:: python
284
class hr_employee(osv.osv):
285
_name = "hr.employee"
286
_description = "Employee"
287
_inherit = "hr.employee"
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'),
295
.. note:: three points
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:
301
.. code-block:: python
303
def _get_cur_function_id(self, cr, uid, ids, field_name, arg, context):
305
#get the id of the current function of the employee of identifier "i"
307
SELECT f.id AS func_id
309
LEFT JOIN res_partner_function f ON (f.id = c.function)
315
sql_res = cr.dictfetchone()
317
if sql_res: #The employee has one associated contract
318
res[i] = sql_res['func_id']
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"
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.
327
:store={...} Enhancement:
329
It will compute the field depends on other objects.
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.
333
:Example In membership module:
335
.. code-block:: python
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)}),
345
.. describe:: Declaring a property
347
A property is a special field: fields.property.
349
.. code-block:: python
351
class res_partner(osv.osv):
352
_name = "res.partner"
353
_inherit = "res.partner"
355
'property_product_pricelist': fields.property(
358
relation='product.pricelist',·
359
string="Sale Pricelist",·
362
group_name="Pricelists Properties"),
366
Then you have to create the default value in a .XML file for this property:
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)"/>
381
if the default value points to a resource from another module, you can use the ref function like this:
383
<field name="value" eval="'product.pricelist,'+str(ref('module.data_id'))"/>
385
**Putting properties in forms**
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).
389
Properties are displayed by section, depending on the group_name attribute. (It is rendered in the client like a separator tag).
391
**How does this work ?**
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.
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.
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.
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.
401
**Using properties or normal fields**
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.
406
Here are a few tips to help you choose between a normal field or a property:
408
Normal fields extend the object, adding more features or data.
410
A property is a concept that is attached to an object and have special features:
412
* Different value for the same property depending on the company
413
* Rights management per field
414
* It's a link between resources (many2one)
416
**Example 1: Account Receivable**
418
The default "Account Receivable" for a specific partner is implemented as a property because:
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.
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.
424
* The default account receivable is the same for all partners and is configured from the general property menu (in administration).
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.)
429
**Example 2: Product Times**
431
The product expiry module implements all delays related to products: removal date, product usetime, ... This module is very useful for food industries.
433
This module inherits from the product.product object and adds new fields to it:
435
.. code-block:: python
437
class product_product(osv.osv):
439
_inherit = 'product.product'
440
_name = 'product.product'
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'),
453
This module adds simple fields to the product.product object. We did not use properties because:
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.