소개
Odoo의 모든 입력 화면에는 여러 필드가 있습니다. 어떤 항목은 매번 수동으로 입력해야 하지만, 많은 필드는 합리적인 초기값을 지정해두면 사용자가 빈칸을 채우기 전에 쓸모 있는 상태로 시작할 수 있습니다. 기본값 시스템은 겉으로 보기엔 단순하지만, 설정이나 커스터마이징을 할 때 알아두면 유용한 내부 작동 방식이 여러 층으로 나뉘어 있습니다.
Odoo Studio로 간단히 기본값을 지정하는 비즈니스 사용자이든, 코드로 필드를 다루는 개발자이든 기본값의 동작 원리를 알면 시간을 절약하고 나중에 원인 파악이 어려운 설정 오류를 피할 수 있습니다.
이 문서는 Odoo에서 기본값이 무엇인지, ORM 수준에서 어떻게 적용되는지, 정적(default)과 동적(default) 기본값의 차이, 그리고 Studio와 Python 코드로 각각 어떻게 설정하는지 실무 관점에서 정리합니다.
Odoo에서 기본값이란 무엇인가
Odoo ORM 관점에서 기본값은 새 레코드가 생성될 때 필드에 미리 채워지는 초기값입니다. 제약 조건이 아니므로 사용자는 언제든지 값을 변경할 수 있습니다. 기본값은 단지 사용자에게 의미 있는 시작점을 제공해 폼을 더 바로 쓸 수 있게 해 줍니다.
Odoo의 거의 모든 필드 타입(Char, Integer, Float, Boolean, Date, Many2one, Selection 등)은 default 파라미터를 지원합니다. 기본값은 단순한 리터럴 값이 될 수도 있고, 레코드 생성 시 실행되는 파이썬 람다나 메서드를 가리킬 수도 있습니다. 상황에 맞게 이들 방식을 선택하면 됩니다.
Odoo Studio에서는 필드 속성 패널에 기본값 입력란이 있어 비개발자도 정적 기본값을 쉽게 지정할 수 있습니다. 코드를 쓰지 않고도 데이터 일관성을 높일 수 있어, 간단한 설정 변경이 필요한 경우 가장 접근성이 높은 방법입니다.
데이터베이스 수준에서는 기본값이 필드 컬럼에 고정 저장되는 것이 아닙니다. 기본값은 파이썬 모델 정의나 데이터베이스의 ir.default 레코드에 존재하며, 새 레코드가 생성될 때 Odoo가 이 정보를 읽어 폼을 사전 채웁니다.
기본값이 작동하는 원리
사용자가 새 폼을 열면 프레임워크는 모델의 default_get()를 호출합니다. 이 메서드는 모든 필드의 기본값을 수집해 필드명-값 딕셔너리를 반환하고, 폼은 그 딕셔너리를 기준으로 초기값을 채워 사용자에게 표시합니다.
Odoo에서 기본값은 주로 네 가지 방식으로 나뉩니다. 각각 다른 상황에 적합하니 목적에 맞게 선택하세요.
정적 기본값(Static Defaults)
정적 기본값은 필드 정의에 하드코딩하거나 Studio에서 지정한 고정 값입니다. 예를 들어 Boolean을 기본 True로 두거나 Selection을 'draft'로 설정하는 식입니다. 가장 단순하고 일상적인 요구를 대부분 충족합니다.
람다나 메서드 기반 동적 기본값(Dynamic Defaults via Lambda or Method)
레코드 생성 시점에 실행되는 파이썬 함수나 람다를 이용하면 현재 날짜, 로그인 사용자 등 실행 환경에 따라 기본값을 동적으로 결정할 수 있습니다. 예컨대 현재 사용자를 담당자로 설정하거나 오늘 날짜를 문서 날짜 기본값으로 쓰는 경우가 이에 해당합니다.
다음 예시는 파이썬 모델 정의에서 정적·동적 기본값을 어떻게 선언하는지 보여주는 전형적인 패턴입니다.
from odoo import fields, models
class CrmLead(models.Model):
_inherit = 'crm.lead'
# Static default
x_priority_level = fields.Selection(
[('low', 'Low'), ('medium', 'Medium'), ('high', 'High')],
string='Priority Level',
default='medium',
)
# Dynamic default: current user
x_assigned_by = fields.Many2one(
'res.users',
string='Assigned By',
default=lambda self: self.env.user,
)
# Dynamic default: today's date
x_expected_date = fields.Date(
string='Expected Close Date',
default=lambda self: fields.Date.today(),
)
컨텍스트 기반 기본값(Context-Based Defaults)
액션 컨텍스트에 default_필드명 형식으로 값을 전달하면 해당 키가 기본값으로 적용됩니다. 예를 들어 프로젝트 내에서 새 업무를 만들 때 프로젝트 필드가 자동으로 채워지는 것이 이 메커니즘입니다. 네비게이션 흐름에서 자연스럽게 사용되는 방식으로, 개발자나 고급 사용자가 필요한 컨텍스트 키를 구성해 활용할 수 있습니다.
사용자별 기본값(ir.default)
Odoo는 ir.default 레코드를 통해 사용자별 기본값을 지원합니다. 관리자가 특정 사용자나 회사 범위로 기본값을 설정하면 그 사용자가 새 레코드를 만들 때 모델 수준의 기본값보다 우선 적용됩니다. 팀마다 작업 습관이 다를 때 유용한 기능입니다.
우선순위 정리
동일 필드에 여러 기본값 출처가 존재하면 Odoo는 다음 순서로 우선순위를 결정합니다: 사용자별 ir.default → 회사 범위의 ir.default → 모델에 정의된 Python 기본값. 실행 시 전달되는 컨텍스트 기반 기본값은 모델 기본값을 덮어씁니다. 이 순서를 알면 폼을 열었을 때 기대한 값이 보이지 않을 때 원인을 찾는 데 도움이 됩니다.
업무 적용 사례
기본값은 Odoo의 거의 모든 모듈에서 쓰입니다. 다음은 실무에서 자주 만나는 다섯 가지 사례입니다.
CRM: 신규 리드의 기본 영업 담당자 설정
영업 담당자가 새 리드나 기회를 생성할 때 담당자(Responsible) 필드를 현재 로그인한 사용자로 기본 지정하면, 모든 리드가 미할당 상태로 시작하지 않아 따로 할당하는 수고를 줄일 수 있습니다. 모델에서 lambda self: self.env.user로 설정하면 사용자가 자신의 리드를 바로 확인할 수 있어 CRM 사용률이 올라갑니다.
영업: 주문의 기본 결제 조건
판매 주문을 생성할 때 고객의 결제 조건(예: Net 30)이나 가격 목록(pricelist)이 자동으로 채워지면 매번 수동으로 선택할 필요가 없어 오류가 줄어듭니다. 고객 설정에 따라 일관된 조건이 적용되므로 여러 영업 담당자가 주문을 생성해도 계약 조건이 흔들리지 않습니다.
재고: 전송 시 기본 위치 자동 입력
내부 이동이나 재고 조정 시 출발지/도착지 위치가 창고 설정에 맞춰 기본값으로 들어가면 동일 구역에서 작업하는 직원은 폼을 열자마자 올바른 위치를 확인할 수 있어 클릭 수가 줄고 급할 때 잘못된 위치를 선택하는 위험이 낮아집니다.
회계: 전표의 기본 분개장 설정
매입/매출 전표를 만들 때 전표 유형과 회사 설정에 맞는 적절한 분개장이 자동으로 선택되면 회계 담당자가 매번 분개장을 찾지 않아도 됩니다. 이 기본값은 하드코딩된 값이 아니라 회사 설정에서 동적으로 결정되므로 분개장이 재구성되더라도 올바르게 동작합니다.
프로젝트: 새 작업의 기본 스테이지
프로젝트 내에서 새 작업을 만들면 해당 프로젝트의 첫 번째 스테이지로 시작합니다. 특정 프로젝트 레코드에서 버튼을 눌러 작업을 생성하면 컨텍스트 기반 기본값으로 프로젝트와 담당자가 미리 채워지는 경우도 있습니다. 이렇게 하면 작업이 처음부터 올바른 칸반 위치에 놓여 팀의 워크플로가 흐트러지지 않습니다.
기본값 생성 및 커스터마이징 방법
Odoo에서 기본값을 설정하는 방법은 크게 세 가지로 나뉘며, 접근성은 코드 없음(Studio)에서부터 코드 전용(Python)까지 다양합니다.
Odoo Studio 사용(코드 불필요)
Odoo Studio는 폼의 어떤 필드든 시각적으로 기본값을 지정할 수 있는 인터페이스를 제공합니다. Studio에서 기본값을 정하려면 다음 절차를 따릅니다.
- 수정하려는 폼에서 Studio를 엽니다.
- 구성하려는 필드를 클릭합니다.
- 오른쪽 필드 속성 패널에서 Default Value 입력란을 찾습니다.
- 원하는 시작값을 입력하거나 선택합니다.
- 저장 후 Studio를 종료합니다.
Studio는 이 설정을 데이터베이스의 ir.default 레코드로 저장합니다. 별도 제약이 없다면 회사 전체에 적용되며, 사용자 범위를 제한할 수도 있습니다. Selection, Boolean, Char, Integer 필드의 정적 기본값에 특히 유용하고, Many2one은 드롭다운에서 기존 레코드를 선택하는 방식으로 처리됩니다. 코드를 작성하지 않고 필드를 빠르게 개선할 때 가장 실용적인 방법입니다.
주의할 점: Studio로 기본값을 변경해도 이미 생성된 기존 레코드의 값은 바뀌지 않습니다. 새 기본값은 변경 이후 생성되는 레코드에만 적용됩니다.
기술적 커스터마이징에서의 파이썬 사용
개발 환경에서는 필드 정의 안에 직접 default를 넣어 정적 값, 람다, 메서드 기반 동적 기본값을 모두 제어합니다. 런타임 정보(현재 사용자, 오늘 날짜, 회사 설정 등)에 따라 기본값이 달라져야 할 때 이 방법이 선호됩니다.
다음 예시는 커스텀 모듈에 추가할 수 있는 여러 형태의 기본값 예시입니다.
from odoo import fields, models
class SaleOrder(models.Model):
_inherit = 'sale.order'
# Static Boolean default
x_requires_review = fields.Boolean(
string='Requires Review',
default=False,
)
# Static Selection default
x_delivery_preference = fields.Selection(
[('standard', 'Standard'), ('express', 'Express')],
string='Delivery Preference',
default='standard',
)
# Dynamic default using a method
def _default_note(self):
return self.env['ir.config_parameter'].sudo().get_param(
'sale.default_note', default=''
)
x_internal_note = fields.Text(
string='Internal Note',
default=_default_note,
)
이 패턴은 Odoo의 일반적인 파이썬 필드 관례를 따르며 모든 필드 타입에 적용됩니다. 특히 메서드 기반 기본값은 람다 하나로 해결하기엔 로직이 복잡할 때 유용합니다.
프로그램으로 ir.default 레코드 생성/변경
XML-RPC API나 모듈의 데이터 파일을 통해 ir.default 레코드를 프로그래밍으로 만들거나 업데이트할 수도 있습니다. 설치 시점에 기본 설정을 함께 배포해야 하는 커스텀 모듈에서 유용합니다. ir.default 모델은 모델명, 필드명, 값과 선택적으로 회사나 사용자 스코프를 받습니다.
이 방식은 일상적인 개발에서는 덜 사용되지만, 설치 루틴에 기본값을 포함시켜 배포해야 할 때 종종 활용됩니다.
Odoo 기본값 사용 모범 사례
필수 필드에 기본값 지정
필드가 필수(required)라면 가능한 경우 합리적인 기본값을 제공하세요. 그러면 사용자가 새 레코드를 저장하려다 필수값 누락으로 오류를 겪는 일이 줄어듭니다. required=True와 실용적인 기본값을 함께 쓰는 패턴이 좋습니다.
날짜 기본값엔 람다 사용
날짜를 기본값으로 고정하는 것은 안 됩니다. lambda self: fields.Date.today()를 사용하면 레코드 생성 시점의 현재 날짜가 항상 들어갑니다. 하드코딩한 날짜는 곧바로 틀리게 되므로 절대 권장하지 않습니다.
기본값 로직은 가볍게 유지
기본값 함수는 레코드가 생성될 때마다, 즉 사용자가 새 폼을 열 때마다 실행됩니다. 따라서 DB 조회나 외부 API 호출처럼 무거운 작업을 실행하지 마세요. 기본값은 빠르고 단순하게 유지하고, 복잡한 로직이 필요하면 onchange나 계산(compute) 필드로 옮기는 것이 낫습니다.
네비게이션 흐름엔 컨텍스트 기본값 사용
새 폼을 여는 커스텀 액션이나 버튼을 만들 때는 모델 기본값에 의존하기보다 액션 컨텍스트에 default_필드명을 전달하세요. 네이티브 Odoo 버튼이 작동하는 방식과 일치하며 프레임워크 관행에 맞는 구현입니다.
여러 사용자 프로필로 기본값 검증
self.env.user나 self.env.company를 참조하는 동적 기본값은 로그인한 사용자나 회사에 따라 동작이 달라집니다. 최소 두 명 이상의 사용자 계정과 멀티컴퍼니 환경이 있다면 각기 다른 설정으로 테스트하세요. 관리자로는 정상 작동해도 일반 사용자에게는 의도치 않은 결과가 나올 수 있습니다.
자주 발생하는 실수들
가변 객체를 기본값으로 쓰지 말 것
클래식한 파이썬 실수입니다. default=[]나 default={}처럼 가변 객체를 직접 쓰면 그 객체가 모든 인스턴스 사이에서 공유되어 데이터 유출이 발생합니다. 대신 default=lambda self: []처럼 레코드 생성마다 새로운 객체가 생성되도록 하세요.
기본값은 onchange를 트리거하지 않음
기본값을 설정해도 해당 필드의 onchange 메서드는 자동으로 실행되지 않습니다. 따라서 기본값으로 채워진 필드 때문에 연쇄적으로 업데이트돼야 할 다른 필드가 있다면, 초기화 시에 명시적으로 default_get를 오버라이드해 onchange를 호출하거나 다른 방식을 사용해야 합니다.
ir.default와 모델 정의의 충돌
Python 코드와 Studio(또는 ir.default)에서 같은 필드에 각각 기본값을 설정하면 우선순위 때문에 혼란이 생깁니다. 이 경우 ir.default가 모델 수준 기본값을 덮어쓰므로, Studio에서의 변경이 개발자가 코드에 적어둔 값을 조용히 무효화하는 상황을 자주 목격하게 됩니다.
기본값이면 필수가 아니다라는 착각
기본값이 설정되어 있다고 해서 필드가 자동으로 필수로 취급되진 않습니다. 사용자가 필드를 지우면 빈값으로 저장됩니다. 항상 값이 필요하다면 기본값과 함께 required=True를 설정해 데이터 완전성을 강제하세요.
회사나 사용자 레코드 ID를 하드코딩하지 말 것
default=1처럼 특정 DB ID를 직접 참조하면 환경마다 ID가 달라 깨질 가능성이 큽니다. 대신 lambda self: self.env.company.id나 lambda self: self.env.ref('module.xml_id').id처럼 동적으로 참조하세요.
결론
기본값은 작지만 강력한 도구입니다. 수작업 입력을 줄이고 사용자가 일관된 선택을 하게 도우며 폼을 더 직관적으로 만들어 줍니다. Studio로 빠르게 설정하든 파이썬 코드로 정교하게 구현하든, 기본값 동작을 이해하면 더 나은 Odoo 도입과 운영이 가능합니다.
핵심 요약: 기본값은 레코드 생성 시에만 적용되며 지속적으로 실행되지 않습니다. 기본값은 onchange를 트리거하지 않습니다. 여러 출처의 기본값은 정해진 우선순위로 결정됩니다. 리스트나 딕셔너리 같은 가변 객체는 람다로 감싸 새로 생성해야 합니다.
기본값을 제대로 쓰면 사용자가 새 레코드를 만들 때마다 느끼는 불편함이 크게 줄어듭니다. 약간의 설계 노력으로 매일 쌓이는 시간을 절약하고 실수를 줄일 수 있는 투자입니다.
Dasolo에서는 기업의 워크플로에 맞춘 Odoo 도입, 커스터마이징, 최적화를 지원합니다. 필드 기본값 설정, 커스텀 필드 개발, 실무에 맞는 데이터 모델 설계가 필요하면 도와드리겠습니다. 문의하기 귀사의 Odoo 도입 상황을 함께 논의해보겠습니다.