4. Odoo 기술 & 개발(Tech, Architecture)/커스텀 모듈 개발 & API

SQL 없이 데이터 다루는 Odoo ORM 기초: 실무 핵심 메서드 7가지 완벽 정리

wegosolution 2026. 8. 29. 18:34

Odoo 개발 및 커스터마이징을 시작할 때 가장 핵심이 되는 기술은 ORM(Object Relational Mapping)입니다. ORM을 활용하면 복잡한 PostgreSQL SQL 쿼리를 직접 작성하지 않고도 파이썬(Python) 객체 문법을 통해 데이터베이스를 직관적이고 안전하게 조작할 수 있습니다.

1. Odoo ORM 동작 구조: Python과 PostgreSQL 사이의 통역사

Odoo ORM은 파이썬 비즈니스 로직 코드와 백엔드 PostgreSQL 데이터베이스 사이에서 SQL 변환 통역사 역할을 담당하는 계층입니다. 개발자가 모델 기반 파이썬 코드를 실행하면 ORM이 이를 최적화된 SQL로 변환하여 실행하고, 결과를 파이썬 객체인 레코드셋(Recordset)으로 반환합니다.

단계 처리 계층 주요 역할 및 기술적 설명
Python Code self.env['model.name'].method() 형식으로 작성되는 비즈니스 로직. 데이터 처리 의도를 파이썬 문법으로 전달.
Odoo ORM 파이썬 코드를 분석하여 안전한 PostgreSQL SQL 쿼리로 자동 변환하고 트랜잭션 및 보안 권한을 관리하는 미들웨어.
PostgreSQL Database 클라우드 인프라 및 서버 환경에 저장된 실제 관계형 테이블. 생성된 SQL이 최종 실행되는 스토리지 계층.

직접 SQL을 실행하지 않으므로 문법 오류를 원천 차단하며, 파라미터 바인딩을 통해 SQL 인젝션(SQL Injection) 취약점을 완벽히 방어합니다.

odoo-orm-architecture-and-common-methods
Odoo ORM Basics

 

2. 실무 필수 Odoo ORM 메서드 7가지

Odoo ORM 메서드는 데이터 0건, 1건, 다건 모두 동일한 인터페이스로 처리할 수 있는 레코드셋(Recordset)을 기반으로 동작합니다.

create(vals): 신규 레코드 생성

새로운 데이터 레코드를 생성할 때 사용하는 메서드입니다. 인자로는 필드명과 값이 매핑된 딕셔너리를 전달합니다.

Python
# res.partner 모델에 신규 파트너 생성
new_partner = self.env['res.partner'].create({
    'name': 'Amit',
    'email': 'amit@example.com'
})
  • 반환값: 방금 생성된 단일 레코드셋 객체가 반환되어 후속 필드 접근이 즉시 가능합니다.

search(domain): 조건 검색 (SQL WHERE 대체)

조건식(Domain) 리스트를 기반으로 데이터베이스에서 조건에 일치하는 데이터를 조회합니다.

Python
# state가 'sale'인 확정 판매주문 조회 (AND 조건 기본 적용)
confirmed_orders = self.env['sale.order'].search([('state', '=', 'sale')])
  • 도메인 구조: [(필드명, 연산자, 비교값)] 형태의 튜플 리스트로 작성합니다.

browse(ids): ID 기반 직접 인메모리 조회

이미 알고 있는 Primary Key(ID) 값을 바탕으로 데이터베이스 조회 없이 레코드셋을 즉각 생성합니다.

Python
# ID 1, 2, 3번 파트너 레코드셋 인스턴스화
partners = self.env['res.partner'].browse([1, 2, 3])
  • 특징: 실제 데이터 조회는 필드 값에 접근하는 시점(Lazy Loading)에 발생하므로 메모리 및 쿼리 효율이 뛰어납니다.

write(vals): 레코드 일괄 수정

기존 레코드셋의 필드 값을 딕셔너리 형태로 전달받아 일괄 갱신(UPDATE)합니다.

Python
# 레코드셋 내 모든 레코드의 name 필드 일괄 변경
record.write({'name': 'New Name'})

unlink(): 레코드 영구 삭제

데이터베이스에서 해당 레코드셋을 완전히 제거(DELETE)합니다.

Python
# 레코드 삭제 실행
record.unlink()
  • 엔지니어링 팁: 데이터 정합성과 감사(Audit) 관리를 위해 실무에서는 unlink() 대신 active = False 처리나 상태 변경 방식을 권장합니다.

mapped(field_name): 특정 필드값 추출

레코드셋을 순회하는 별도의 for 루프 없이 특정 필드의 값만 리스트 형태로 빠르게 추출합니다.

Python
# 모든 파트너의 이메일 목록 리스트 반환 (점 표기법으로 Relation 탐색 가능)
email_list = partners.mapped('email')

filtered(func): 메모리 내 조건 필터링

데이터베이스에 추가 쿼리를 보내지 않고, 이미 메모리에 로드된 레코드셋을 파이썬 람다(Lambda) 함수로 걸러냅니다.

Python
# 메모리 상에서 회사(is_company=True)인 파트너만 필터링
company_records = partners.filtered(lambda p: p.is_company)

 

3. ORM 쿼리 분석 및 레코드셋 체이닝(Chaining)

"확정된(sale) 주문 데이터 조회" 작업 시 ORM이 실행되는 내부 구조는 다음과 같습니다.

Python
self.env['sale.order'].search([('state', '=', 'sale')])
  • self.env: 사용자 ID, 보안 컨텍스트, DB 커서 환경이 포함된 실행 환경 객체입니다.
  • ['sale.order']: 데이터 조작 대상 모델의 기술적 명칭(Model Name)입니다.
  • .search([('state', '=', 'sale')]): PostgreSQL 내부적으로 SELECT * FROM sale_order WHERE state = 'sale' 형태의 쿼리로 안전하게 변환되어 실행됩니다.

메서드 체이닝 예시

레코드셋의 특징을 활용하면 복잡한 가공도 파이썬 한 줄 코드로 간결하게 처리할 수 있습니다.

Python
# 회사(Company)인 파트너들의 이름 목록만 한 줄로 추출
company_names = partners.filtered(lambda p: p.is_company).mapped('name')
핵심 메서드 실행 위치 목적
create / search / write / unlink PostgreSQL (SQL 쿼리) 데이터 영속성 관리 및 DB I/O 수행
mapped / filtered Python Application (In-Memory) 메모리 상의 레코드셋 고속 가공 및 변환