blog image

some important methods in doo

 1. name_get() method

we can override name_get() method to get customized rec_name of particular dataset.

def name_get(self):
    result=[]
    for rec in self:
        name=rec.seq_num+"-["+rec.name+"]"
        result.append((rec.id,name))
    return result

#note: seq_num and name is the attribute of the particular model

 

2. default_get()

 This method is used get default values in record

there are basically three way to get the default value

1.pass through context

2.add default value in models fields 

3.default_get method in form view

@api.model
def default_get(self,fields):
    # default_get method is already create in model so we call it's super method
    country_lst=[1,2,3,4,5] 
    lst=[]
    countries=self.env['res.country'].search([('name','=','nepal')],limit=1)
    for c in countries:
        lst.append(c.id)
        
    res=super(Model_name,self).default_get(fields)
    #res is in dictionary form with default field and value
    #if you want to set other deafult value then you can aslo do that 
    res['full_name']="amrit panta"
    res['gender']='male'  #selection type
    res['department_id']=record.id, #many2one type
    res['is_active']=True #boolean type
    res['country_ids']=[(6,0,country_lst)] # from many2many
    res['countries']=[(6,0,lst)] # from many2many
    res['subjects_ids']=[
                    (0,0,{"name":"nepal","mark":100})
                    (0,0,{"name":"english","mark":100})
                         
                         ]

 

3.

 

 

 here we will learn extra concept in odoo

 

how to load make sequence number in odoo

for this we will need one .xml file to defile sequence number in odoo.so we will make on .xml file inside data folder  as appointment_seq.xml.

<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <data noupdate="1">
        <record id="seq_appointment" model="ir.sequence">
            <field name="name">Appointment Sequence</field>
            <field name="code">hospital.appointment</field>
            <field name="prefix">AS</field>
            <field name="padding">5</field>
            <field name="company_id" eval="False"/>
        </record>
    </data>
</odoo>

Note: here noupdate="1" and code name is important as code name is used to link this file to particular model field to access this file.

then we will link this on model filed as 

class HospitalAppointment(models.Model):
    _name = 'hospital.appointment'
    _description = 'Appointments'
    _order = "id desc"


    name = fields.Char(string='Appointment Reference', required=True, copy=False, readonly=True,
                       default=lambda self: _('New'))

    @api.model
    def create(self, vals):
        if not vals['description']:
            vals['description'] = "Enter the description here"
        if vals.get('name', _('New')) == _('New'):
            vals['name'] = self.env['ir.sequence'].next_by_code('hospital.appointment') or _('New')

        res = super(HospitalAppointment, self).create(vals)
        return res

 

onchnage function in odoo

@api.onchange('patient_id')
    def _change_appointment_note(self):
        if self.patient_id:
            if not self.note:
                self.note = "New appointment"
        else:
            self.note = ""

 

how to run python function on clicking on button in odoo

for this first you need to make button on .xml file according to your requirement as below and mention button name to make run

<button id="button_done" name="action_status_done" string="Done" class="btn-success" type="object"
                            confirm="Are you sure you want to set done?"/>


    def action_status_done(self):
        self.status = 'done'

how to make status bar  in odoo

<header>

<field name="status" widget="statusbar" statusbar_visible="draft,confirm,done,cancel"
 options="{'clickable':'1'}"/>

</header>

you need to defile status field in models for the statusbasr like

    status = fields.Selection([
        ('draft', 'Draft'),
        ('confirm', 'Confirmed'),
        ('done', 'Done'),
        ('cancel', 'Canceled')
    ], default='draft', required=True, tracking=True)

how to perform validation in odoo

from odoo.exceptions import ValidationError   
import re
 @api.constrains('appointment_date', 'checkup_date')
    def _check_date_validation(self):
        for record in self:
            if record.checkup_date < record.appointment_date:
                raise ValidationError('Checkup date should not be previous date.')

 @api.constrains('email')
    def _check_email(self):
        for record in self:
            valid_email = re.match('^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z] 
                                                                            {2,4})$',record.email)

            if valid_email is None:
                raise ValidationError('Please provide a valid E-mail')

 @api.constrains('age')
    def _check_doctor_age(self):
        for record in self:
            if record.age <= 0:
                raise ValidationError('Age must be greater than 0')


 @api.constrains('name', 'phone')
    def _check_patient_exists(self):
        for record in self:
            patient = self.env['hospital.patient'].search(
                [('name', '=', record.name), ('phone', '=', record.phone), ('id', '!=', 
                                                                                    record.id)])
            if patient:
                raise ValidationError(f'Patient {record.name} already exists')

 

related model argument in odoo

    patient_id = fields.Many2one("hospital.patient", string='Patient Name', required=True)
    gender = fields.Selection([
        ('male', 'Male'),
        ('female', 'Female')
    ], related='patient_id.gender')
    phone = fields.Char(string='Phone', related='patient_id.phone')
    email = fields.Char(string='Email', related='patient_id.email')
    age = fields.Integer(string='Age', related='patient_id.age')

how to calculate compute function in odoo

  total_appointments = fields.Integer(string='No. of appointments', compute='_compute_appointments')


  def _compute_appointments(self):
        for record in self:
            record.total_appointments = self.env['kmhospital.appointment'].search_count(
                [('patient_id', '=', record.id)])

 

onchnage function in odoo


    def action_url(self):
        return {
            "type": "ir.actions.act_url",
            "url": "https://github.com/KamrulSh/km_hospital",
            "target": "new",
        }

 

Schedule action in odoo

seetings>technical>Automation>schedule Actions

inorder to make cron job in odoo you need to make record with necessary information. which is shown below:

1.create one file inside the data folder for instance cron.xml

<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <data>
        <record id='incompleted_task_cron' model='ir.cron'>
            <field name='name'>schedule:Incompleted Task</field>
            <field name='model_id' ref='model_onboarding_task_assign'/>
            <field name='type'>ir.actions.server</field>
            <field name='state'>code</field>
            <field name="code">model.incompleted_task()</field>
            <field name="interval_number">1</field>
            <field name="interval_type">days</field>
            <field name="numbercall">-1</field>
            <!-- which user account will execute the cron job. -->
            <field name="user_id" ref="base.user_root"/>
            <!-- <field name="nextcall" eval="(DateTime.now() + timedelta(days=1)).strftime('%Y-%m-%d 21:30:00')" /> -->
            <field name="nextcall" eval="(DateTime.now().replace(hour=17, minute=50, second=0, microsecond=0))" />
            <!-- specifies whether the cron job should catch up on all missed executions if the server was down. -->
            <field eval="True" name="doall"/>
        </record>
    </data>

</odoo>

     
            
         

2.mention thius file in manifest file and define function that you mention on specific model as 
 

 @api.model            
    def incompleted_task(self):
         #logic a/c to requirements

3.then you can test from schedule actions under automation section in technical menu of general settings

 

 

 

 

 how to call python function by menu or serevr actions

Basically we have two type of action in odoo

1.Basic action

this action is used to acll views through ir.actions.act_window

 

2.Server action

we might have a scenario where we need to call python function through menu . this time server action comes in hand.

    <record id="server_action_id" model="ir.actions.server">
        <field name="name">Student</field>
        <field name="model_id" ref="module_name.model_your_model_name"/>
        <!-- you can get ref syntax example from .csv file of your model it.model.access.csv -->
        <field name="state">code</field>
        <field name="code">model.call_by_menu</field>

    </record>


    <!-- we will make menu and call above action as  -->
    <menuitem
        id="model_name_menu"
        name="name"
        action="server_action_id"
        parent="parent_id"
        sequence="10"/>
    

    <!-- then in python file , define function  -->
    def call_by_menu(self):
        pass 

 

 

 

 

@api.model

The @api.model decorator in Odoo is used to define methods that are called on the model itself rather than on a specific record of the model. This type of method is commonly known as a "class method" in other programming languages. These methods do not operate on individual records and typically perform operations that are related to the model as a whole, such as creating new records, performing bulk operations, or implementing business logic that does not depend on the context of a specific record.

Key Points about @api.model

  1. No Record Context: Methods decorated with @api.model do not have access to specific records. They are called on the model itself.
  2. Database Operations: They can be used to perform database operations, like creating, searching, or modifying records, but do not operate on the individual record data.
  3. Self Parameter: The self parameter in @api.model methods represents the model and not a specific recordset. It's typically an empty recordset of the model.

Common Use Cases

  1. Creating Records: Defining custom behavior when creating records.
  2. Searching Records: Implementing complex search logic.
  3. Performing Batch Operations: Operations that affect multiple records or require processing without reference to individual records.
  4. Utility Methods: General utility functions that relate to the model but do not require access to record-specific data
from odoo import models, fields, api

class SchoolStudent(models.Model):
    _name = 'school.student'
    _description = 'Student'

    name = fields.Char(string='Name')
    student_id = fields.Char(string='Student ID')

    @api.model
    def create(self, vals):
        # Custom logic before creating a record
        vals['student_id'] = self.env['ir.sequence'].next_by_code('school.student') or '/'
        return super(SchoolStudent, self).create(vals)


    @api.model
    def search_students_by_name(self, name):
        return self.search([('name', 'ilike', name)])


   @api.model
    def get_default_country(self):
        # Return the default country set in the system
        return self.env.user.company_id.country_id

 

@api.model_create_multi

The @api.model_create_multi decorator in Odoo is used to create multiple records of a model efficiently. This decorator is particularly useful when you need to create several records of the same model in one go, rather than creating them one by one. It ensures that the creation process is optimized for bulk operations, improving performance compared to creating records individually.

Key Points about @api.model_create_multi

  1. Decorator Purpose: @api.model_create_multi optimizes the creation of multiple records by allowing them to be created in bulk.

  2. Use Case: It's typically used in scenarios where you need to create a batch of records of the same model, such as during data migration, batch processing, or when importing data.

  3. Performance: Using @api.model_create_multi can significantly improve performance over creating records iteratively, especially when dealing with a large number of records.

 

from odoo import models, fields, api,_

class SchoolStudent(models.Model):
    _name = 'school.student'
    _description = 'Student'

    name = fields.Char(string='Name')
    age = fields.Integer(string='Age')

    @api.model_create_multi
    def create_students(self, student_data_list):
        # student_data_list should be a list of dictionaries, each containing data for a student
        for vals in student_data_list:
            if not vals.get('dob'):
               raise ValidationError(_("DOB  is  needed"))
        students = self.create(student_data_list)
        return students

 

Example:

# Assuming 'self.env' is an Odoo environment variable accessible within the script or method
students_model = self.env['school.student']
students_data = [
    {'name': 'John', 'age': 20},
    {'name': 'Mary', 'age': 22},
    {'name': 'Jane', 'age': 21},
]

created_students = students_model.create_students(students_data)

 

 

 

How to add new states to an existing state field

class PurchaseOrderInherit(models.Model):
    _inherit = 'purchase.order'
    
    state=fields.Selection(selection_add=[('wait','wait')])

 

 

 

 

color in odoo

<tree decoration-success="state=='done"></tree>
<field name="tag_ids" widget='many2many_tags' options="{'color_field':'color'}"/>
<field name="state" decoration-success="state=='done" decoration-info="state=='draft'"  widget='badge'/>
<field name="docker_id" decoration-success="1" decoration-info="gender=='male'" optional='show' decoration_bf="1" widget='many2one_avatar_user'/>

 

 

for color color=fields.Integer() so widget='color_picker'

color=fields.char() so widget='color'

 

 

 

 

 

noupdate attribut in odoo

if clients make some changes and then we upgrade module it will not show that but initial daata which are loaded are showing. so 

we can use noupdate attribute.

 

forcecreate="0"

for all every record forcecreate is True, for client delete some data then upgrade module it will again shown.

 

 

 

How to call python function by the menu or server actions

we use basic action to all menu => ir.action.act_window

but when  we want to call python function through menu we used the server actions=> ir.actions.server

 

    <record id="action_python_function_calll_server_actions" model="ir.actions.server">
    <field name="name" >Server Actions</field>
    <field name="model_id" ref="school.model_school_student_extra"/>
    <field name="state">code</field>
    <field name="code">action=model.call_function_through_menu()</field>    
    </record>

    <menuitem
        id="servr_action_menu"
        name="Server action"
        action="action_python_function_calll_server_actions"
        parent="school_menu"
        sequence="100"/>

then tyou can define function according to your requirements.

 

 

 

How to get default value in the form view:

there are basically 3 ways

1.pass value in context

2.add default="" vlaue while defining field

3.default_get method in form view

 

 

    @api.model
    def default_get(self, fields):
        res = super(StudentExtraInfo, self).default_get(fields)
        res['age']='100'
        res['gender']='male'
        nepal_country=self.env['res.country'].search([('name','=','Nepal')],limit=1)
        res['country']=nepal_country.id # for many2one
        '''
        country_ids=[]
        for rec in countries:
             country_ids.append(rec.id)
        res['countries']=[(6,0,country_ids)]  # for many2many
        
        # for one2many
        res['staff_line_ids']=[
            (0,0,{'name':'test','product_id':2}),
            (0,0,{'name':'testing','product_id':2}),
        ]
        '''
        return res

 

Different between onchange and compute function

onchange: only on current value

compute: all records, old record as well

 

 

context="{'search_default_filter_male':1}

context="{'search_default_group_by_male':1}

<group expand="0" string="Group By">

<filter string="Account Type" name="accounttype" domain="" context="{'group_by':'account_type'}"/>

</group>

<searchpanel class="account_root">

<field name="root_id" icon="fa-filter" limit="0"/>

<field name="gender" string="" enable_counter="1" icon="fa-building" select="multi" />

</searchpanel>

 

related and compute field is not store in database by default if you  need you need to add Store=True

<tree create="0" delete="0" edit="0" duplicate="0"

all else and other condition must be define in the computed field code to avoid the error

docoration-success="state=='draft'"

decoration-info="state=='draft' or state=='ongoing'"

decoration-warning="state in ('draft','ongoing')

 

 

<tree name="activity_ids" widget="list_activity"/>

 

widget="many2one_avatar"

 

collabrative HTml field

<field name='description' options={'collaborative':true,'resizable':true,'codeview':true}/>

default focus attribute  default_focus="1"

show sample data in odoo view in tree in background of the tree view

sample="1"

 

enable multi editing in odoo list view

<tree multi_edit="1">

<button type='object' states='draft,ongoing'>

show button only on mention state

 

 

 

show fiels only on the debugger mode

<field name='name' groups='base.group_no_one'/>

once developer mode is activate , user is added to base.group

 

activity view in odoo??

hide one2many field base on the (parent)condition

 

<tree>

<field name="address" attrs="{'column_invisible':[('parent.hide_sales_price','=',True)]}"/>

here parent is the syntax and in parent model hide_sales_price=fields.Boolean() must be present 

 

 

you can also inherit the funx=ction as well as

def action_confirm(self):

     res=Super(classname,self).action_confirm()

     self.confirm_user_id=self.env.user.id

    return res

 

target inline (in action)

<field name="target"> inline</field> # create ,edit buttn will not shown now

 

odoo environment

self

self.model_id

self.env

self.env.user

self.env.is_system

self.env.is_admin

self.env.is_superuser

self.env.company

self.env.companies

self.env.lang

self.env.cr

self.env.context

self.env['school.student'].browse(25).name

self.env['school.student'].browse(25).action_done() # function of the model

self.env.ref('module_name.external_id').name

 

 

<odoo>
    <record id="action_set_all_records_inactive" model="ir.actions.server">
        <field name="name">Set All Records Inactive</field>
        <field name="model_id" ref="model_your_model"/>
        <field name="binding_model_id" ref="model_your_model"/>
        <field name="state">code</field>
        <field name="code">
            action = env['your.model'].set_all_records_inactive()
        </field>
    </record>
</odoo>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


About author

author image

Amrit Panta

Python developer, content writer



3 Comments

Amanda Martines 5 days ago

Exercitation photo booth stumptown tote bag Banksy, elit small batch freegan sed. Craft beer elit seitan exercitation, photo booth et 8-bit kale chips proident chillwave deep v laborum. Aliquip veniam delectus, Marfa eiusmod Pinterest in do umami readymade swag. Selfies iPhone Kickstarter, drinking vinegar jean.

Reply

Baltej Singh 5 days ago

Drinking vinegar stumptown yr pop-up artisan sunt. Deep v cliche lomo biodiesel Neutra selfies. Shorts fixie consequat flexitarian four loko tempor duis single-origin coffee. Banksy, elit small.

Reply

Marie Johnson 5 days ago

Kickstarter seitan retro. Drinking vinegar stumptown yr pop-up artisan sunt. Deep v cliche lomo biodiesel Neutra selfies. Shorts fixie consequat flexitarian four loko tempor duis single-origin coffee. Banksy, elit small.

Reply

Leave a Reply

Scroll to Top