1 Odoo development cheatsheet
Matt Marcha edited this page 2025-11-05 09:59:56 -10:00

Odoo development cheatsheet

Datetime & Timezones

  • All datetime are stored in UTC in database
  • fields.Datetime are in UTC. They are only displayed in the user's timezone

Fetching data with specific timezone

This is tricky. If for whatever reason the datetime value cannot be send directly from the UI (and so be automatically converted), the value has to be converted in the code.

import pytz


## Get the timezone first. This is retrieved from context then user, then default. Can be set in another way
timezone = pytz.timezone(self.env.context.get('tz') or self.env.user.tz or 'UTC')
## Create a localized datetime from the date source
date_tz = timezone.localize(fields.Datetime.from_string("1988-05-16 16:55:00"))

## Now get an UTC datetime from the localized one
start = date_tz.astimezone(pytz.timezone('UTC'))
## If needed, set up an end date from the starting one
end = start + relativedelta(years=36)

# Retrieve the data 
awesome_guy_ids = self.env['sale.report'].search(['&',
   ('date', '>=', start),
    ('date', '<', end),
])

Display date on context timezome

If for whatever reason (reports, typically), the date is displayed in UTC instead of the contaxt timezone, use :

fields.Datetime.context_timestamp(self, date)

Command line interface

You can get the cli with the command odoo shell . From there, it is possible to manipulate odoo objects and use the env variable. This can be very useful for debugging, or sometimes to manipulate data.

In case you want your data manipulation to be persisted, you need to commit with env.cr.commit()

WARNING : This is likely to have consequences. It is not recommended to do such operation in production.

An example :

users = env['res.user'].browse([1,2,3]) #fetch problematic users
users.unlink() #delete them
env.cr.commit() #needed to 

View behavior depending to current user's group

It is not possible to access env, user or similar vars in ir.view records. To get different field behaviors depending on current user's group, you need to register several ir.view records (potentially inheriting the previous one) and use the ir.view field groups_id to limit the record to specific groups. Example :

<!-- Switch a field readonly for everyone -->
<record id="view_account_payment_register_form" model="ir.ui.view">
    <field name="name">account.payment.register.form.inherit.perp</field></field>
    <field name="model">account.payment.register</field>
    <field name="inherit_id" ref="account.view_account_payment_register_form"/>
    <field name="arch" type="xml">
        <xpath expr="//field[@name='payment_date']" position="attributes">
            <attribute name="readonly">1</attribute>
        </xpath>
    </field>
</record>

<!-- Same field is not readonly for admin though -->
<record id="view_account_payment_register_form_admin" model="ir.ui.view">
    <field name="name">account.payment.register.form.inherit.perp.admin</field>
    <field name="model">account.payment.register</field>
    <field name="inherit_id" ref="account.view_account_payment_register_form"/>
    <field name="groups_id" eval="[(4, ref('base.group_system'))]"/>
    <field name="arch" type="xml">
        <xpath expr="//field[@name='payment_date']" position="attributes">
            <attribute name="readonly">0</attribute>
        </xpath>
    </field>
</record>

Hide product's Internal Reference

Use the context display_default_code=False. This can be achieved on multiple levels (model field, view, action...)

Inherit name_search function on the related model. To customise from a specific view/action/model, add a context to check on name_search to rewrite the search results To avoid huge load on db, limit results to 8 as the quick search only display 8 results.