Introdução
Na maioria das implementações Odoo, ligações entre registos são feitas com campos Many2one — simples e eficientes quando o destino é sempre o mesmo modelo. Porém, há cenários em que a origem pode apontar para vários tipos de documento conforme o contexto: uma encomenda de venda, um pedido de compra, um apontamento de produção, entre outros. Para esses casos flexíveis existe o campo Reference.
O campo Reference é um tipo de campo polimórfico do ORM do Odoo que permite referenciar um registo pertencente a qualquer um dos modelos definidos numa lista de seleção. Em vez de fixar a ligação a um único modelo, o utilizador escolhe primeiro o tipo de documento e depois o registo concreto, criando assim uma referência que se adapta a vários fluxos de trabalho.
Neste artigo explico o que o campo guarda internamente, como se comporta na base de dados, como o pode criar tanto via Odoo Studio como em código Python, e situações do dia a dia em que esta solução traz vantagem real para o negócio.
O que é o campo Reference no Odoo
No núcleo do Odoo, o Reference é um campo que contém a referência a um registo de qualquer modelo incluído na sua lista de seleção (selection). Ao contrário do Many2one, que aponta sempre para um modelo fixo, o Reference é desenhado para suportar ligações polimórficas entre objetos distintos.
Na base de dados, o valor do Reference é guardado como uma string no formato nome_modelo,id_do_registo. Por exemplo, uma referência para a encomenda de venda 42 aparece como sale.order,42. Esse detalhe é fundamental quando for necessário consultar ou filtrar estes campos diretamente no PostgreSQL.
Na interface, o Reference funciona em dois passos: primeiro o utilizador seleciona o tipo de documento (por exemplo: Encomenda de Venda, Fatura, Tarefa), depois procura e escolhe o registo específico desse modelo. Para quem usa, a experiência torna-se simples assim que se percebe a sequência de escolha.
Exemplo de definição básica de um Reference em Python:
from odoo import fields, models
class HelpDeskTicket(models.Model):
_inherit = 'helpdesk.ticket'
related_document = fields.Reference(
selection=[
('sale.order', 'Sale Order'),
('purchase.order', 'Purchase Order'),
('account.move', 'Invoice'),
('project.task', 'Project Task'),
],
string='Related Document',
)
O parâmetro selection é uma lista de tuplos: o nome técnico do modelo (ex.: sale.order) e a etiqueta legível pelos utilizadores que aparece no menu. É aqui que define, de forma precisa, que modelos estarão disponíveis para seleção.
Também pode tornar a lista dinâmica: em vez de uma lista fixa, a seleção pode ser preenchida a partir da tabela ir.model em tempo de execução, tornando disponíveis todos os modelos instalados. Útil em ferramentas altamente configuráveis, mas pode sobrecarregar o utilizador se não for filtrada correctamente.
No Odoo Studio, o campo aparece no painel de tipos com o nome Reference. Ao adicioná-lo pelo Studio, consegue configurar quais os modelos permitidos sem escrever código, o que facilita muito personalizações rápidas por analistas de negócio.
Como funciona este campo
Compreender como o Reference guarda e recupera informação é essencial para o usar corretamente nos seus projectos Odoo.
Armazenamento na base de dados
Ao contrário do Many2one — que armazena apenas a chave estrangeira inteira — o Reference guarda uma string com o par modelo,id (por exemplo, sale.order,15) numa coluna VARCHAR. Por isso não existe uma restrição de foreign key a nível de base de dados; esta escolha permite a natureza polimórfica do campo.
Como não há chave estrangeira, o Odoo não elimina automaticamente referências quando o registo apontado é apagado. Se eliminar uma encomenda, um campo Reference que apontava para ela permanecerá com a string antiga, criando valores órfãos que convém gerir deliberadamente no seu projecto.
Aceder ao registo referenciado em Python
Quando lê um Reference em código Python, o ORM resolve-o e devolve o objecto record do modelo referenciado — exactamente como um Many2one faria em termos de uso. Se o campo estiver vazio, retorna False.
ticket = self.env['helpdesk.ticket'].browse(1)
doc = ticket.related_document
if doc:
print(doc._name) # e.g. 'sale.order'
print(doc.name) # e.g. 'S00042'
print(doc.id) # e.g. 15
Apesar do armazenamento textual, a camada ORM traduz essa string num record object quando acede ao valor, o que facilita trabalhar com os campos e atributos do registo referenciado de forma natural em código Python.
Principais atributos do campo
Estes são os atributos mais relevantes que pode configurar num campo Reference no Odoo:
- selection: Lista de tuplos que define os modelos seleccionáveis. Pode também ser o nome de um método (string) que devolve essa lista dinamicamente.
- string: Rótulo do campo mostrado na interface.
- required: Define o campo como obrigatório — o utilizador terá de escolher tipo e registo antes de guardar.
- readonly: Torna o campo apenas leitura na interface. Útil quando a referência é definida por lógica de negócio e não deve ser alterada pelo utilizador.
- help: Texto de ajuda exibido ao passar o rato sobre o rótulo, para orientar o utilizador sobre o que seleccionar.
- compute: Pode ser calculado por um método Python como qualquer outro campo, permitindo definir a referência automaticamente conforme regras de negócio.
Filtragem e pesquisa
Como o valor é uma string, as pesquisas por domínios têm de usar essa mesma sintaxe. Para localizar registros ligados a um documento específico deve compor a string completa:
tickets = self.env['helpdesk.ticket'].search([
('related_document', '=', 'sale.order,15')
])
Também pode filtrar apenas pelo tipo de modelo usando um operador like:
tickets = self.env['helpdesk.ticket'].search([
('related_document', 'like', 'sale.order,')
])
Tenha sempre em conta este comportamento baseado em texto quando desenhar relatórios, campos computados ou quaisquer filtros que dependam de valores Reference — não se comportam como domínios de Many2one convencionais.
Casos práticos de utilização
O campo Reference é mais útil quando a mesma ligação precisa de apontar para diferentes tipos de documentos dependendo do contexto. Abaixo estão cinco exemplos práticos onde ele traz valor real no dia a dia de empresas.
1. Tickets de suporte ligados a qualquer documento
Uma equipa de suporte pode precisar relacionar um ticket com facturas, encomendas, entregas ou contratos. Em vez de criar campos separados para cada tipo de documento, um único Reference no ticket permite que o agente seleccione o tipo e o registo relevante, mantendo a informação centralizada e simples de gerir.
2. Actividades de CRM com origem variada
Tarefas de seguimento comercial podem nascer de diferentes fontes — um lead, um orçamento, um contrato ou um caso de suporte. Um campo Reference em actividades CRM permite marcar qual foi o documento de origem sem ficar preso a um único modelo, tornando o registo histórico mais completo e flexível.
3. Notas e anotações transversais
Ao criar um modelo de notas internas, é comum querer anexar a mesma nota a clientes, tarefas de projecto, ordens de fabrico ou pedidos de compra. Um Reference permite usar um único modelo de nota para diferentes objectos, evitando duplicação e facilitando pesquisas posteriores.
4. Fluxos de aprovação genéricos
Numa solução de aprovação genérica, os pedidos podem referir-se a ordens de compra, relatórios de despesas, pedidos de ausência ou contratos. Colocar um Reference no modelo de aprovação simplifica a lógica: a mesma rotina de aprovação trata todos os tipos de documento sem multiplicar modelos.
5. Despesas associadas a projecto ou encomenda
Em contabilidade, uma despesa pode pertencer quer a um projecto quer a uma encomenda de venda conforme o tipo de custo. Um Reference com project.project e sale.order na sua seleção dá ao contabilista a flexibilidade para relacionar a despesa ao documento correcto, algo útil em serviços profissionais e consultoria.
Criar ou personalizar um campo Reference
Existem duas formas principais de adicionar um campo Reference: via Odoo Studio para uma solução sem código ou directamente em Python para controlo total.
Via Odoo Studio
O Studio permite adicionar um Reference a um formulário sem tocar em código. Abra o Studio no modelo que deseja estender, escolha um novo campo do tipo Reference e seleccione, pela interface, quais os modelos disponíveis. O campo criado pelo Studio recebe um prefixo x_, como acontece com os outros campos gerados pelo editor visual.
Esta abordagem é ideal para personalizações rápidas feitas por analistas de negócio. Note, contudo, que campos criados pelo Studio podem ter limitações para funcionalidades avançadas como selection dinâmico ou cálculo por código.
Implementação técnica em Python
Para controlo total e manutenção profissional, defina o campo em código Python no módulo. Abaixo um exemplo que demonstra o uso de um método para popular dinamicamente a selection:
from odoo import api, fields, models
class ApprovalRequest(models.Model):
_name = 'approval.request'
_description = 'Approval Request'
name = fields.Char(string='Request Name', required=True)
@api.model
def _get_document_types(self):
return [
('purchase.order', 'Purchase Order'),
('hr.expense.sheet', 'Expense Report'),
('hr.leave', 'Time Off Request'),
('sale.order', 'Sale Order'),
]
document_ref = fields.Reference(
selection='_get_document_types',
string='Document',
help='Select the document this approval relates to.',
)
Usar um método para selection (passando o nome do método como string) dá-lhe flexibilidade para adicionar lógica condicional, filtrar consoante módulos instalados ou montar a lista a partir de registos de configuração.
Criar via API XML-RPC
Também é possível criar um campo Reference através da API XML-RPC — útil para deployments automatizados. O tipo de campo a usar é reference e a selection é passada como uma string com a representação Python da lista.
field_id = models.execute_kw(
ODOO_DB, uid, ODOO_API_KEY,
'ir.model.fields', 'create',
[{
'name': 'x_related_document',
'field_description': 'Related Document',
'model_id': model_id,
'ttype': 'reference',
'selection': "[('sale.order', 'Sale Order'), ('purchase.order', 'Purchase Order')]",
'state': 'manual',
}]
)
Ao criar o campo via API, a selection é passada como string avaliável, que é como o Odoo persiste essa informação na tabela ir.model.fields. Tenha isso em conta nas suas rotinas de deployment.
Boas práticas
Recomendações práticas ao trabalhar com Reference fields
- Mantenha a lista de selection curta e relevante. Incluir todos os modelos apenas porque é possível só complica a vida ao utilizador; escolha os tipos de documento que fazem sentido para o processo em causa.
- Use Many2one quando a ligação for sempre ao mesmo modelo. O Reference é para relações polimórficas; se nunca troca de modelo, um Many2one é mais simples e eficiente para relatórios e consultas.
- Verifique sempre valores nulos em campos computados. Se o Reference estiver vazio, em Python devolve
False. Qualquer código que aceda ao registo referenciado deve validar isso para evitar exceções. - Trate referências órfãs com ações automatizadas. Como a base de dados não garante integridade referencial, é recomendável criar ações agendadas que detectem e limpem referências para registos eliminados.
- Use etiquetas descritivas na seleção. O segundo elemento do tuplo é o que o utilizador vê — prefira termos de negócio como "Fatura de Cliente" em vez de nomes técnicos como
account.move. Isso melhora a usabilidade e reduz erros de seleção. - Documente claramente a escolha técnica. Explique nas especificações porque foi escolhido um Reference em vez de um Many2one e liste os modelos ligados — isso ajuda qualquer desenvolvedor que herde o projecto a compreender a arquitectura.
Erros comuns a evitar
Erros que ocorrem com frequência ao usar Reference fields
Usar domínios como se fosse um Many2one
Um erro recorrente é escrever domínios assumindo que o valor é um inteiro — por exemplo [('document_ref', '=', 15)]. Isso não funciona porque a coluna contém strings no formato modelo,id. Deve compor a string completa ao filtrar por registo específico.
Esquecer que registos apagados deixam valores órfãos
Ao eliminar um registo referenciado, o valor textual permanece. Ler esse Reference depois pode devolver False em vez de causar um erro. Qualquer lógica que dependa da validade da referência tem de prever este comportamento e tratar referências inválidas.
Abusar da seleção dinâmica com todos os modelos
Popular a selection com todos os modelos instalados (a partir de ir.model) pode parecer conveniente, mas na prática apresenta centenas de opções ao utilizador e conduz a escolhas incorrectas. Sempre restrinja a lista a modelos realmente relevantes ao caso de uso.
Contar com agrupamentos nativos em relatórios
Como os Reference são strings, não funcionam com group-by/pivot nativos como um Many2one. Se precisar agrupar por tipo de documento, crie um campo calculado que extraia o nome do modelo ou represente-o como um selection separado para suportar agregações.
Confundir Reference com Many2one no Studio
No Studio alguns utilizadores escolhem o tipo errado porque ambos ligam a outros registos. A diferença essencial é: Many2one fixa o modelo no desenho do campo; Reference deixa o utilizador escolher o modelo por registo. Se criou um Many2one quando precisava de um Reference, terá de recriar o campo corretamente.
Conclusão
O campo Reference resolve uma limitação do Many2one: quando precisa de apontar para diferentes tipos de documento com a mesma lógica, ele evita duplicação de modelos e regras. É simples de definir, compatível com Odoo Studio para soluções sem código e plenamente integrável em módulos Python para implementações técnicas.
Os pontos cruciais a reter são o formato de armazenamento em string, a ausência de limpeza automática por foreign key e a necessidade de compor strings ao filtrar por IDs. Com estes aspetos claros, o campo comporta-se de forma previsível e segura dentro do seu modelo de dados Odoo.
Seja para um workflow de aprovação genérico, para ligar tickets de suporte a diversos documentos, ou para criar um sistema de notas transversal a vários módulos, o Reference oferece uma solução limpa e fácil de manter sem duplicar lógica por cada tipo de modelo.
Precisa de ajuda com a sua implementação Odoo?
Na Dasolo acompanhamos empresas na implementação, personalização e otimização do Odoo para que a ferramenta se alinhe com processos reais. Desde desenho de modelos de dados até desenvolvimento de funcionalidades específicas, temos experiência técnica para entregar soluções robustas e escaláveis.
Se está a trabalhar num projecto Odoo e precisa de orientação sobre tipos de campos, arquitectura de dados ou práticas de desenvolvimento, contacte-nos. Podemos avaliar a sua situação e propor uma abordagem adequada ao seu contexto.