Odoo의 readonly 필드는 처음엔 단순해 보이지만, 실제로는 시스템 안정성·감사·업무 흐름에 큰 영향을 미치는 핵심 요소입니다.
특정 항목이 회색으로 표시돼 수정할 수 없는 이유를 궁금해하는 비즈니스 사용자든, 필드 동작을 세밀하게 제어하려는 개발자든 이 가이드는 필요한 핵심 지식을 모두 제공합니다.
readonly 필드의 작동 원리를 이해하면 워크플로의 신뢰성 확보, 데이터 무결성 보호, 그리고 사용자의 업무 효율 개선에 직접 기여할 수 있습니다.
이 튜토리얼은 비즈니스 관점과 기술 관점을 함께 다루므로, 설정만 하는 관리자든 모듈을 개발하는 엔지니어든 실무에 바로 적용할 수 있는 내용을 제공합니다.
Odoo에서 readonly 필드란 무엇인가
Odoo에서 readonly 필드는 화면에 값은 보여주되 사용자가 직접 입력하거나 수정할 수 없도록 잠근 필드를 말합니다. 읽기 전용으로 표시되어 값은 보이지만 입력이 차단됩니다.
폼 뷰에서는 readonly 필드가 입력 상자 대신 일반 텍스트처럼 표시됩니다. 테마에 따라 옅게 회색으로 보이거나 평평한 스타일로 렌더링되어 편집 가능 필드와 시각적으로 구분됩니다.
Odoo에서 readonly 동작은 두 가지 수준에서 적용할 수 있다는 점을 이해하는 것이 중요합니다:
- 모델(ORM/Python) 수준: 필드를 모델 정의에서 아예 readonly로 지정하면 모든 뷰와 컨텍스트에서 항상 읽기 전용입니다.
- 뷰(XML) 수준: 특정 뷰나 조건에서만 해당 필드를 읽기 전용으로 설정할 수 있습니다.
이 둘의 차이를 구분해야 합니다. ORM 수준에서 readonly로 설정한 필드는 사용자 인터페이스를 포함한 모든 경로에서 쓰기가 차단됩니다. 반면 뷰 수준의 readonly는 해당 뷰 안에서만 편집을 막을 뿐, 다른 뷰나 서버 사이드에서는 쓰기가 가능할 수 있습니다.
readonly는 별도의 필드 타입이 아니라 기존 Odoo 필드 타입(Char, Integer, Float, Many2one, Date 등)에 붙이는 속성입니다. 이 속성으로 런타임 동작을 제어하는 것이 프레임워크의 기본 메커니즘입니다.
readonly 속성은 어떻게 동작하나
readonly 필드의 동작을 이해하려면 데이터 모델(ORM/Python)과 화면(View/XML) 두 측면을 모두 살펴보는 것이 도움이 됩니다.
ORM(모델) 수준의 readonly
ORM에서는 필드를 Python 모델에서 영구적으로 readonly로 선언할 수 있습니다. 보통 다른 필드에서 값이 계산되는 computed 필드에 이 설정을 사용합니다. 필드 정의에 readonly=True를 주면 UI에서 절대 수정할 수 없습니다.
이 설정은 Odoo의 Python 필드 API의 일부이며 공식 개발자 문서에 정리되어 있습니다. 어떤 뷰를 사용하든 전역적으로 적용됩니다.
상태(state)에 따른 readonly 처리
Odoo에서 가장 흔한 패턴 중 하나는 문서의 상태에 따라 필드를 readonly로 바꾸는 것입니다. 예컨대 견적서나 주문이 초안(draft)을 벗어나면 특정 필드를 잠가서 이후 변경을 막는 방식입니다.
Odoo 16 이전에서는 뷰 XML의 attrs 속성으로 도메인 조건을 조합해 구현했지만, Odoo 17 이후에는 필드 요소에 바로 인라인 표현식을 써서 더 간결하게 표현합니다.
두 방식 모두 같은 결과를 만듭니다: 문서가 초안인 동안은 편집 가능하고, 워크플로가 진행되면 필드가 잠깁니다. 이는 필드 설정을 다루는 모든 기술 문서에서 기본으로 다뤄지는 개념입니다.
계산(computed) 필드와 readonly
Odoo의 computed 필드는 기본적으로 readonly입니다. compute 메서드로 값이 자동 계산되는 필드는 사용자가 직접 입력하도록 허용되지 않는 것이 기본 가정입니다.
계산 필드를 데이터베이스에 저장하려면 compute와 함께 store=True를 지정합니다. 이렇게 저장된 필드는 검색이나 정렬 성능에서 유리해 실무에서 자주 사용하는 패턴입니다.
계산 필드를 쓰기 가능하게 만들기
계산 필드에 사용자의 직접 입력을 허용하려면 inverse 메서드를 함께 정의해야 합니다. inverse는 사용자가 값을 쓸 때 어떻게 역으로 다른 필드에 반영할지 정의합니다. inverse가 없으면 기본적으로 readonly가 유지됩니다.
실무 적용 사례
readonly 필드는 거의 모든 Odoo 모듈에 걸쳐 사용됩니다. 다음은 실무에서 자주 마주치는 다섯 가지 사례입니다.
1. CRM: 수주/실패 기회 데이터 고정
CRM에서는 기회가 진행되는 동안에는 예상 매출이나 닫는 날짜를 수정할 수 있지만, 기회가 Won 혹은 Lost로 상태 변경되면 그 시점의 값들을 잠가 기록을 보존합니다.
이렇게 하면 이후에 누군가 임의로 수치나 종료 시점을 바꿔 파이프라인 분석이나 성과 보고서를 왜곡하는 일을 막을 수 있습니다.
2. 판매: 확정 주문 항목 보호
판매주문이 초안에서 확정으로 넘어가면 주문 라인은 readonly로 설정되어 상품, 수량, 가격을 사용자가 바꿀 수 없습니다.
정당한 수정이 필요하면 주문을 다시 초안으로 되돌려야 하며, 이 과정은 의도적인 수정이라는 감사 흔적을 남깁니다.
3. 재고: 확정된 입출고 수량 잠금
창고 작업에서 배송이나 입고가 검증되면 실제 처리된 수량이 잠깁니다. 이는 재고 평가와 실제 물동량 기록의 일치를 보장하기 위함입니다.
검증 이후에 수량을 자유롭게 바꿀 수 있다면 여러 위치의 재고 수치가 조용히 어긋날 위험이 있습니다.
4. 회계: 게시(posted)된 분개 라인 고정
회계에서는 분개가 게시되면 그 라인이 모두 readonly가 됩니다. 많은 국가에서 법적 요구사항이고, 복식부기 원칙을 지키기 위한 핵심 관행입니다.
게시 후 수정이 허용되면 재무제표의 신뢰성이 훼손되고 규제 리스크가 발생할 수 있습니다.
5. 제조: 완료된 작업지시 기록 보호
제조 모듈에서 작업지시가 완료되면 실제 소요시간과 생산수량은 readonly로 설정됩니다. 이는 제조 원가 분석과 성과 추적의 기초 데이터로 사용됩니다.
readonly 필드 생성 및 커스터마이징 방법
Odoo에서 readonly 필드를 설정하는 방법은 크게 두 가지입니다: 코드 없는 접근인 Odoo Studio를 쓰는 방법과, 직접 Python/XML로 구현하는 기술적 방법입니다.
Odoo Studio로 설정하기
Odoo Studio는 코드를 쓰지 않고도 readonly 설정을 간단히 추가·수정할 수 있게 해 줍니다. Studio에서 readonly를 켜는 절차는 다음과 같습니다.
- 메인 메뉴에서 Odoo Studio(연필 아이콘)를 엽니다
- readonly를 적용할 폼 뷰로 이동합니다
- 수정하려는 필드를 클릭합니다
- 오른쪽 속성 패널에서 'Readonly' 옵션을 토글합니다
- 저장하고 Studio를 닫습니다
Studio에서는 상태나 값에 따라 조건부 readonly를 도메인 표현식으로 설정할 수도 있습니다. 예를 들어 상태 필드가 특정 값일 때만 읽기 전용으로 만드는 조작을 코드 없이 구현할 수 있습니다.
간단한 규칙을 빠르고 안전하게 적용해야 하는 컨설턴트나 관리자에게 Studio 기반 필드 설정은 적합합니다. Studio 변경 사항은 데이터베이스에 저장되며 모듈 업그레이드로 덮어씌워지지 않습니다.
개발자를 위한 Python 기반 커스터마이징
커스텀 모듈을 개발하는 경우 Python 모델에서 필드 정의에 readonly 속성을 직접 설정합니다. 이것은 표준 Odoo 필드 사용 방식이며 개발자 문서에 상세히 나와 있습니다.
readonly=True를 필드 파라미터로 주면 영구적으로 편집 불가능하게 할 수 있습니다. 더 유연한 제어가 필요하면 states 파라미터로 어떤 상태에서 읽기/쓰기 가능한지 정의할 수 있습니다.
이 방식은 기존 모델에 커스텀 필드를 추가하거나 데이터 모델 중심의 로직을 유지하고자 할 때 유리합니다. 필드 규칙이 모델 근처에 모여 있어 관리하기 쉽습니다.
뷰(XML) 속성으로 처리하기
뷰 수준에서 readonly를 적용하려면 뷰 XML의 필드 요소에 readonly 속성을 추가하면 됩니다. 기술적 커스터마이징의 표준 워크플로우입니다.
뷰 레벨의 장점은 유연성입니다. 같은 필드라도 서로 다른 뷰나 상황에서 다르게 동작하게 할 수 있어, Python 모델을 변경하지 않고 화면 단에서 제약을 걸 때 유용합니다.
Odoo 17에서는 readonly 조건을 표현하는 인라인 문법이 이전의 attrs 방식보다 더 읽기 쉽고 간결합니다. 사용하는 Odoo 버전에 따라 적합한 방법을 선택하면 됩니다.
권장 실무(베스트 프랙티스)
readonly를 잘 활용하려면 적절한 수준에, 적합한 이유로 적용하는 것이 핵심입니다. 다음은 컨설팅 관점에서 권장하는 실무 가이드입니다.
1. 맥락이 다양할 때는 뷰 수준에서 적용하라
필드가 특정 상태나 뷰에서만 readonly여야 한다면 모델 수준이 아니라 뷰 수준에 적용하세요. 이렇게 하면 백엔드 프로세스나 API 통합이 필요할 때 필드에 쓰기를 유지할 수 있어 유연성이 확보됩니다.
2. readonly 조건을 문서 라이프사이클과 맞춰라
필드가 잠기는 시점은 문서의 흐름과 자연스럽게 일치해야 합니다. 문서가 특정 단계에 도달했을 때만 잠기도록 하면 사용자의 예측 가능성이 높아지고 시스템 사용성이 좋아집니다.
3. 사용자 역할별로 반드시 테스트하라
readonly 동작은 접근 권한과 엮이면 의외의 결과를 낳을 수 있습니다. 일반 사용자와 관리자로 각각 테스트해 어떤 역할에서 어떻게 동작하는지 확인하세요.
4. 필요한 경우 readonly와 required를 조합하라
다단계 폼에서는 초안 단계에 필드를 필수(required)로 받고 이후 단계에서 readonly로 전환하는 패턴이 유용합니다. 배송일이나 참조번호처럼 확인 전에 반드시 입력해야 할 필드에서 자주 사용됩니다.
5. readonly 로직을 문서화하라
복잡한 커스텀 모델에서는 왜 특정 필드가 readonly인지 주석으로 남기세요. 다음에 코드를 유지보수하는 개발자가 비즈니스 이유를 쉽게 알 수 있어 변경의 위험을 줄입니다.
6. 빠른 변경은 Studio로, 복잡한 조건은 코드로
단순한 요구사항은 Odoo Studio로 빠르게 해결하고 업그레이드 안정성을 확보하세요. 교차 필드 조건이나 커스텀된 계산 필드와 연동되는 복잡한 로직은 Python 커스터마이징이 필요합니다.
자주 발생하는 실수들
경험 있는 사용자와 개발자도 readonly 관련 문제로 발목을 잡힐 때가 많습니다. 미리 알고 있으면 당황을 줄일 수 있는 대표적인 함정들입니다.
뷰 수준의 readonly를 보안 경계로 오해하지 말 것
뷰에 readonly를 걸었다고 해서 XML-RPC API, ORM write 호출, 또는 서버 액션을 통한 업데이트까지 막히는 것은 아닙니다. 뷰 수준은 UI 제약일 뿐, 진짜 쓰기 금지는 ORM 레벨 또는 접근 제어 규칙으로 강제해야 합니다.
조건부로 두어야 할 필드를 영구적으로 readonly로 만들어 버리는 실수
필드를 완전히 잠가 버리면 초안으로 되돌려 수정해야 하는 합법적 시나리오까지 막힐 수 있습니다. 전체 라이프사이클을 고려해 영구 잠금과 조건부 잠금 중 무엇이 적절한지 결정하세요.
onchange 메서드를 잊지 말 것
readonly 필드가 onchange에서 참조되면 해당 메서드가 값을 할당하려 시도할 수 있습니다. 이 때문에 화면에서 값이 잠깐 바뀌는 듯 보이거나 오류가 발생할 수 있으니 onchange 로직에서 readonly를 고려해 처리하세요.
모든 뷰에 일관되게 적용하지 않는 점
폼 뷰에서만 readonly로 설정했더니 트리(list)뷰나 칸반(kanban)에서는 여전히 편집 가능한 경우가 있습니다. 필드가 등장하는 모든 뷰에서 설정이 일관된지 확인하세요.
표준 모델을 상속하면서 의도치 않은 부작용 발생
표준 모델을 상속해 기존 필드에 readonly=True를 추가하면 해당 필드를 사용하는 모든 뷰에 영향이 갑니다. 의도한 변경인지, 표준 동작이나 다른 커스터마이제이션과 충돌하지 않는지 확인하세요.
마무리
readonly 필드는 사용자를 올바른 흐름으로 인도하고, 데이터 무결성을 지키며, 비즈니스 규칙을 기술적으로 강제하는 데 핵심적인 수단입니다.
모델 수준과 뷰 수준 중 언제 어느 쪽에 readonly를 적용할지 판단하고, 조직의 실제 업무 흐름에 맞춰 조건을 설계하는 것이 중요합니다. 잘 설계된 데이터 모델은 적절한 시점에 readonly를 통해 안정성과 사용성을 함께 제공합니다.
Odoo Studio로 빠르게 설정하든, Python·XML로 직접 구현하든 readonly의 논리는 동일합니다: 데이터를 보여주되 실수나 악의적 변경으로부터 보호하라.
많이 언급되지는 않지만, 맞춤화 영향력 측면에서는 조용히 가장 큰 효과를 내는 요소 중 하나입니다.
저희 Dasolo는 다양한 모듈과 산업 전반에서 Odoo 도입·커스터마이징·성능 최적화를 지원합니다. 필드 설정, 신뢰성 있는 워크플로 설계, 데이터 모델 개선이 필요하시면 도움을 드릴 수 있습니다. 문의하기 프로젝트에 관해 이야기해 주세요.