Odoo 13 — In-Memory ORM — Impacto do novo ORM nos seus módulos
Explicamos as principais novidades do novo ORM In-Memory neste outro artigo Odoo 13 — In-Memory ORM — A maior refatoração do core desde o OpenERP 8 e agora vamos mergulhar nos detalhes e seus impactos na prática.
Durante o Odoo Experience o Raphael Collet(do time do Framework do Odoo), em seu talk, evidenciou alguns dos detalhes desta mudança, ressaltando que essa iniciativa foi iniciada pelo Fabien Pinckaers (presidente e fundador da Odoo SA) e que, depois de muito esforço, o convenceu que isto seria possível.
IMPORTANTE: Apesar das mudanças serem fantásticas, a maioria das alterações foi feita de forma invisível no ORM, ou seja, o impacto no seu código é usualmente muito pequeno.
Qual a Motivação?
- Deixar os módulos mais fáceis de programar;
- Performance;
- Mais performance;
- Ainda mais performance;
Super User Mode
O modo super usuário é uma maneira do programador desviar de todas as regras de acesso para realizar uma operação.
Por exemplo: um estoquista precisa emitir uma nota fiscal de simples remessa sem ter permissões no faturamento.
Em versões anteriores à versão 13, ao virar um super usuário, você tem dois problemas:
- Perda da rastreabilidade pois a operação é realizada com o ADMIN;
- Caso você não preencha o contexto corretamente, qual empresa, linguagem e etc. Você terá problemas!
Agora todo usuário tem um modo SUPER USUÁRIO, que permite ao programador desviar das permissões, mantendo o contexto e o ID do usuário:
- env.uid usuário atual;
- env.su flag para superuser mode;
- sudo() troca para o modo super usuário;
- with_user(ID) altera para outro usuário, de um modo não super usuário;
Todos os campos calculados agora são realizados em modo SUPER USUÁRIO, o atributo compute_sudo=True é ativo por padrão.
Cache
Redução das consultas SQL com melhor gerenciamento do cache
Apenas um cache para todos os environments:
- Menores perdas de cache;
- Reflete o conteúdo do banco de dados;
- Cache próximo ao formato psycopg2;
É possível ter inconsistências:
- Mesmo cache para todos os usuários, inclusive em modo super usuário;
- Mesmo cache para todos os contextos;
“Technically, in Odoo 13, computed fields can be context dependent. The cache contains the value of the different context. So, you won’t have inconsistencies. If you read the same computed field in another context, you’ll get another value computed, as expected, as in Odoo 12.” Comentário do Fabien neste mesmo post.
Este é um ponto de atenção importante, pois algumas vezes você pode ter inconsistências no cache dependendo do usuário e a operação a ser realizada. Quando você cair nesta situação, você deve invalidar o cache.
Delayed updates
Método write() não atualiza o SQL da tabela, somente o método flush(), que ao ser chamado também realiza:
- Todos os recálculos: recompute();
- Updates SQL agrupados, para minimizar suas respectivas quantidades;
Alguns métodos de CRUD fazem flush() automaticamente:
- unlink: chamado antes e depois;
- search: através do _flush_search;
- read;
- read group: através do _flush_search;
É imprescindível ler o arquivo parts/odoo/odoo/models.py procurando por chamadas do flush;
As requisições automaticamente realizam flush() antes de commitar;
Flush explícito
A única modificação necessária para migração ou desenvolvimento de códigos com SQL manual é executar um flush com os campos utilizados na query para garantir que os campos estarão no banco de dados.
Campos Calculados
Os erros de leitura mudaram
Se você não conseguir ler um campo, ele apenas não é colocado como vazio, sem criar uma exceção. Caso algum usuário com mais permissões tenha acessado o registro anteriormente, os dados são copiados para cache, e o usuário sem permissões verá os dados.
Recorrendo ao exemplo anterior, o estoquista emite a nota fiscal de simples remessa através do super usuário, os dados são copiados para o cache e mesmo depois de sair do modo super usuário, o estoquista ainda consegue acessar os dados.
Dependência explícita de contexto (depends_context)
Caso você tenha um método que dependa do contexto, não esqueça de decorar o método com o novo decorator @depends_context(). Você pode precisar utilizar alguns argumentos especiais:
- Special key “uid”: (env.uid, env.su);
- Special key “company”: env.company (antigo force_company);
Delayed recomputations
Comportamento padrão é marcar os campos que devem ser recalculados para cálculo posterior e calculá-los somente em duas ocasiões:
- Quando o programador tenta acessar um campo, marcado para ser recalculado;
- Quando é chamado o método flush(), que automaticamente chama o recompute();
Não use manualmente o método recompute(), se você precisar acessar um campo calculado apenas acesse-o, que o ORM cuidará do resto;
Campos calculados com store=True vs store=False
- store=True: não são calculados desnecessariamente, os dados são lidos do cache/banco de dados.
- store=False: Mantém o valor anterior disponível no cache a não ser que sejam explicitamente definidos como False;
Campos calculados como Onchange
Os onchanges serão removidos na versão 14.
Na versão 13 finalmente os campos calculados podem se comportar como campos onchange!!!! Todo programador Odoo que se preze já caiu nessa sinuca de bico.
Seja o exemplo abaixo:
O campo delivery_id só é recalculado quando o campo partner_id é escrito e o delivery_id não é. Então, os seguintes casos podem ocorrer nesse exemplo:
- Somente partner_id é escrito, automaticamente recalcula delivery_id;
- Somente delivery_id é escrito, não recalcula delivery_id;
- partner_id e delivery_id são escritos: não recalcula delivery_id;
Ou seja, o recalculo pode acontecer na criação, escrita e no onchange;
Multi company

O wizard permite selecionar todas as empresas que você deseja visualizar os registros e a sua empresa principal;
- Uma lista com o id das empresas selecionadas no wizard esta disponível no contexto na variável context[‘allowed_company_ids’] ou no recordset env.companies;
- env.company é a empresa selecionada do wizard, com fundo cinza;
Outras recomendações para criar / migrar módulos na versão 13.0
- Atualize-se com as mais recentes convenções da OCA: https://odoo-community.org/page/contributing
- Marque a Versão do módulo para 13.0.1.0.0;
- Remova qualquer script de migração possível da versão anterior;
- Remova todos os decoradores @ api.multi, @ api.returns, @ api.one, @ api.cr, @ api.model_cr do código. Agora todos eles são multi-registro por padrão. No caso dos últimos, você precisará adaptar o código à mudança de comportamento.
- Verifique se todos os métodos de calculo de campos, com store=False, atribuem um valor em qualquer caso ao campo, mesmo que seja False; Os campos armazenados podem manter o valor anterior; [1]
- Substitua sudo(usuário) por with_user (usuário);
- Alguns dos ícones Font Awesome (FA) mudaram de nome, agora que o Odoo usa o FA v5, portanto, pode ser necessário alterá-los nas visualizações do módulo. Verifique os nomes alterados aqui.
- Remova todos os atributos de campo oldname do código. Se eles foram adicionados na versão anterior, eles cumpriram sua função de qualquer maneira, e, agora nesta versão não é suportada. Portanto, se você precisar, crie um script de migração e use o método rename_fields do openupgradelib.
- Remova a tag view_type na definição XML da janela de ação. Agora ele é padrão (a árvore não é suportada desde a versão 11.0).
- Remova o campo multi dos modelos ir.actions.act_window. Agora você tem o campo binding_view_types para indicar em qual visualização a ação estará disponível: lista, formulário ou vazio para ambos.
- Se declarar a ação através da tag simplificada <act_window>, use o atributo binding_views. [3]
- Se estiver usando qualquer precisão decimal em campos float
- No manifesto, renomeie as dependências do python para usar o nome da distribuição do PyPI em vez do nome da importação;[4]
Bom código!
Tenha essas mudanças em mente e não deixe de pesquisar nos módulo do Core e da OCA por mais exemplos.
Referências
[1] (https://github.com/odoo/odoo/pull/36743/commits/2e43bfc1c4b2f61e0459614f61f90a77dc3b7233
[2] https://github.com/OCA/maintainer-tools/wiki/Migration-to-version-13.0
[3] https://github.com/odoo/odoo/pull/24738/commits/33d51480688065e367eb646f12b89d721749cac9.
[4] https://github.com/odoo/odoo/pull/25549 para obter mais informações;