소개
Binary 필드는 화려하진 않지만 실제 Odoo 구축에서는 빠질 수 없는 요소입니다. 계약서 스캔본을 올리고, 제품 데이터시트를 첨부하거나 회사 로고를 레코드에 저장할 때마다 뒤에서 Binary 필드가 파일 데이터를 관리합니다. 파일이 어디에 저장되는지, 어떤 형식으로 다뤄지는지, 언제 다른 필드 유형을 써야 하는지 아는 것은 맞춤 폼을 설계하거나 모델을 확장할 때 성능과 안정성에 큰 차이를 만듭니다.
이 가이드는 Binary 필드가 어떤 데이터를 저장하는지, attachment 모드가 저장 방식과 성능에 어떤 영향을 주는지, Odoo Studio와 Python으로 필드를 생성·조정하는 방법, 그리고 CRM·인사·재고 등 실무에서의 활용 사례를 다룹니다.
Odoo에서 Binary 필드란 무엇인가
Odoo ORM에서 Binary 필드(즉 fields.Binary)는 파일이나 이미지 같은 바이너리 바이트 데이터를 저장하는 용도입니다. 사용자 인터페이스에서는 파일 업로드 버튼으로 보이고, 업로드 후에는 같은 컨트롤로 파일을 내려받을 수 있게 동작합니다.
핵심 기술 포인트는 그 데이터가 실제로 어디에 보관되는가입니다. 최신 Odoo에서는 기본적으로 attachment 모드를 사용해 파일 콘텐츠를 ir.attachment 테이블과 서버의 filestore에 저장하고, 모델 컬럼에는 첨부 레코드의 참조(ID)만 보관합니다. 이렇게 하면 주요 모델 테이블이 비대해지지 않고 Odoo가 파일 관리를 효율적으로 수행할 수 있습니다.
Odoo Studio에서는 필드 선택기에서 해당 필드를 'File'로 표시합니다. 폼 뷰에선 단순한 업로드/다운로드 컨트롤로 렌더링됩니다. 이미지 전용으로는 fields.Image가 있어 자동 리사이즈와 썸네일 미리보기를 지원하니, 이미지 저장용은 이 타입을 고려해야 합니다.
Python 모델 정의에서 Binary 필드가 어떻게 선언되는지 예시로 보여드리면 다음과 같습니다:
from odoo import fields, models
class ResPartner(models.Model):
_inherit = 'res.partner'
x_signed_contract = fields.Binary(
string='Signed Contract',
attachment=True,
)
x_signed_contract_filename = fields.Char(
string='Signed Contract Filename',
)
여기서 주목할 부분은 x_signed_contract_filename 같은 문자열 필드입니다. Binary 필드와 파일 이름용 Char 필드를 한 쌍으로 두는 것은 Odoo에서 일반적인 패턴입니다. _filename 필드는 원본 파일명을 기억해 인터페이스에 보여주기 때문에 없으면 다운로드된 파일명이 'download'처럼 일반명으로 나올 수 있습니다.
필드 동작 원리
모델에 Binary 필드를 정의하면 모듈 설치나 업그레이드 시 Odoo 프레임워크가 자동으로 데이터베이스 컬럼을 처리합니다. 개발자가 직접 SQL을 작성할 필요는 없습니다.
저장 방식(모드)
Binary 필드의 attachment 파라미터는 파일 바이트가 실제로 어디에 저장되는지를 제어합니다:
- attachment=True (권장): 파일 콘텐츠를 ir.attachment에 저장하고 모델명과 레코드 ID로 연결합니다. 모델 컬럼에는 참조 ID만 들어가므로 모델 테이블이 작아지고 Odoo의 filestore를 활용할 수 있습니다.
- attachment=False: base64로 인코딩된 원본 데이터가 모델의 데이터베이스 컬럼에 직접 저장됩니다. 이 경우 테이블이 급격히 커져 쿼리 성능이 떨어지므로 작은 썸네일 정도가 아니라면 피해야 합니다.
데이터 형식
Binary 필드는 데이터를 base64로 인코딩된 문자열 형태로 저장하고 반환합니다. ORM이나 XML-RPC로 읽을 때는 base64 문자열이 돌아오고, 쓸 때도 base64로 인코딩한 값을 전달해야 합니다.
실무에서는 쓰기 전에 인코딩하고, 읽은 뒤 디코딩하는 패턴을 사용합니다:
import base64
# Writing a file to a Binary field
with open('document.pdf', 'rb') as f:
encoded = base64.b64encode(f.read()).decode('utf-8')
record.write({'x_signed_contract': encoded})
# Reading a file from a Binary field
raw_bytes = base64.b64decode(record.x_signed_contract)
중요한 필드 속성
Odoo에서 Binary 필드에 설정 가능한 주요 속성은 다음과 같습니다:
- attachment: Boolean. ir.attachment에 저장할지(True) 컬럼에 직접 저장할지(False)를 결정합니다. 최근 버전 기본값은 True입니다.
- string: 인터페이스에 표시될 레이블.
- required: 레코드 저장 전에 값이 반드시 있어야 하는지 여부.
- compute: 파이썬 메서드로 값을 동적으로 생성할 때 연결합니다. 예를 들어 PDF를 런타임에 생성해 필드에 채우는 경우에 사용합니다.
- store: compute와 함께 쓰일 때 계산된 값을 DB에 저장할지 여부입니다.
- groups: 특정 사용자 그룹만 필드에 접근하도록 제한할 수 있어 민감 문서 관리에 중요합니다.
- copy: 레코드 복사 시 필드 값을 복제할지 제어합니다. attachment 모드나 Odoo 버전별 기본 동작이 다를 수 있습니다.
fields.Image 서브클래스
fields.Image는 Odoo 13에서 도입된 fields.Binary의 특수화 버전으로, 이미지 자동 리사이즈와 썸네일 미리보기 기능, 최대 치수 제한 등을 제공합니다. 제품 이미지·사용자 사진·회사 로고처럼 시각적 자산을 저장할 때는 일반 Binary 대신 fields.Image를 사용하면 과도한 업로드를 막고 사용자 경험을 개선할 수 있습니다.
뷰에서의 표시
폼 뷰에서는 Binary 필드의 기본 위젯이 업로드/다운로드 버튼입니다. 이미지라면 image 위젯을 적용해 썸네일 미리보기를 활성화하세요. 리스트 뷰에는 보통 Binary 필드를 직접 노출하지 않습니다. 각 행마다 파일 전체를 로드하면 불필요한 데이터 전송이 발생하므로 첨부 유무를 나타내는 아이콘이나 불리언 필드로 대체하는 것이 좋습니다.
비즈니스 적용 사례
실제 업무에서 Binary 필드는 여러 모듈에 걸쳐 활용됩니다. 다음은 흔히 볼 수 있는 다섯 가지 사례입니다.
CRM: 고객 레코드에 서명된 NDA/계약서 저장
영업팀은 고객이나 리드에 바로 서명된 계약서를 붙여두기를 원합니다. res.partner나 crm.lead에 Binary 필드를 두면 오피스 외부로 이동하지 않고도 계약서를 한 번의 클릭으로 확인할 수 있어 간단한 문서 관리 요구사항을 충족시킵니다.
인사(HR): 직원 서류 보관
인사팀은 신분증, 취업허가서, 서명된 근로계약서, 교육 수료증 등을 직원 레코드에 저장합니다. hr.employee에 Binary 필드를 두고 groups 속성으로 접근 권한을 제한하면 HR 매니저만 민감한 문서를 열람하게 하는 등 개인정보 보호 요구사항을 충족할 수 있습니다.
재고(Inventory): 제품 사양서·안전보건자료 보관
기술 제품은 제조사 제공의 PDF 사양서나 SDS가 자주 필요합니다. product.template에 Binary 필드를 두면 구매·창고 담당자가 제품 레코드에서 바로 문서를 확인할 수 있어 제조·유통사의 커스터마이즈 요청에 자주 포함되는 기능입니다.
영업: 회사 직인·권한자 서명 이미지
인쇄되는 견적서나 주문서에 회사 직인이나 권한자 서명 이미지를 자동으로 넣어야 하는 경우가 있습니다. res.company에 fields.Image로 저장해 QWeb 리포트에서 참조하면 대량 견적서 발행에서 수작업을 줄이고 서명 누락 위험을 낮출 수 있습니다.
회계: 비용 처리 시 영수증 스캔본 첨부
경비 정산 프로세스에서는 각 비용 항목에 영수증 이미지나 PDF를 첨부하는 것이 일반적입니다. 표준 Odoo 경비 모듈은 첨부 시스템을 기본으로 지원하지만, 커스텀 모델이나 외부 연동 시 Binary 필드를 사용하면 레코드에 파일을 직접 저장하고 승인 흐름에 포함시킬 수 있습니다.
Binary 필드 생성 및 커스터마이즈 방법
Binary 필드를 모델에 추가하는 방법은 기술적 상황과 제어 수준에 따라 크게 세 가지가 있습니다.
Odoo Studio(노코드) 사용
Odoo Studio는 내장된 저코드 도구입니다. 코드를 쓰지 않고 Binary 필드를 추가하려면 다음 절차를 따릅니다:
- 메인 메뉴에서 Odoo Studio를 엽니다.
- 필드를 추가하고 싶은 폼으로 이동합니다.
- 필드 선택기에서 File 필드를 끌어다 폼에 놓습니다.
- 속성 패널에서 레이블과 노출 조건을 설정합니다.
- 저장하고 Studio를 닫습니다.
Studio는 x_studio_ 접두사를 붙여 필드를 생성하고 기본적으로 attachment 모드를 사용합니다. 데이터베이스 설정을 직접 할 필요가 없어 비개발자에게 가장 접근성 좋은 방법입니다.
커스텀 모듈에서 Python 사용
버전 관리와 배포를 고려한 정식 개발은 Python으로 필드를 정의하는 방법이 표준입니다. 생산 환경이나 여러 인스턴스에 배포할 때 권장되는 접근법입니다:
from odoo import fields, models
class HrEmployee(models.Model):
_inherit = 'hr.employee'
x_id_document = fields.Binary(
string='ID Document',
attachment=True,
groups='hr.group_hr_user',
)
x_id_document_filename = fields.Char(
string='ID Document Filename',
)
모델에 필드를 추가한 뒤에는 폼 뷰 XML에 binary 위젯과 filename 속성(파일명용 Char 필드)을 지정하면 됩니다. 모듈 설치나 업그레이드 시 Odoo가 DB 컬럼을 자동으로 생성하므로 Odoo.sh나 온프레미스 모두에서 안정적으로 동작합니다.
XML-RPC API로 생성하기
원격 설정 스크립트나 배포 노트북에서 필드를 프로그래밍으로 만들고 싶다면 XML-RPC API를 통해 필드를 생성할 수 있습니다:
field_id = models.execute_kw(
ODOO_DB, uid, ODOO_API_KEY,
'ir.model.fields', 'create',
[{
'name': 'x_custom_document',
'field_description': 'Custom Document',
'model_id': model_id,
'ttype': 'binary',
'state': 'manual',
}]
)
state: 'manual'로 생성하면 이 필드는 모듈 설치가 아니라 수동으로 생성된 필드임을 Odoo에 알립니다. 최신 버전에서는 API로 만든 필드도 기본적으로 attachment 모드를 사용합니다. 자동화된 인프라 구성이나 원격 배포 워크플로에서 유용한 방법입니다.
권장 관행
1. 항상 attachment=True 사용하기
특별한 이유가 없다면 파일 콘텐츠를 DB 컬럼에 직접 저장하지 말고 attachment 모드를 사용하세요. 모델 테이블이 커지는 것을 방지하고 Odoo의 filestore를 활용해 성능 저하를 막을 수 있습니다. 작은 썸네일을 제외한 모든 실파일은 attachment=True가 기본 원칙입니다.
2. 파일명용 Char 필드 함께 추가하기
Binary 필드를 만든다면 항상 _filename 형태의 Char 필드를 같이 두세요. 그렇지 않으면 다운로드 시 파일명이 일반명으로 나옵니다. 한 줄의 코드로 사용자 경험을 크게 개선할 수 있습니다.
3. 이미지라면 fields.Image 사용
제품 사진, 인물 사진, 로고 등은 반드시 fields.Image를 사용하세요. 업로드 크기를 제한하고 썸네일을 제공해 인터페이스와 저장 공간 관리를 개선합니다. 콘텐츠 유형에 맞는 필드 타입 선택은 깔끔한 데이터 모델 설계의 핵심입니다.
4. groups로 접근 제한 설정하기
직원 문서나 계약서처럼 민감한 파일은 groups 속성으로 접근을 제한하세요. 누가 읽고 쓸 수 있는지 제어하는 것은 개인정보 보호와 규정 준수를 위해 필수입니다.
5. 코드에서 base64 인코딩을 정확히 처리하기
프로그램으로 Binary 필드를 읽고 쓸 때는 base64 처리에 신경 써야 합니다. 쓰려면 base64.b64encode(file_bytes).decode('utf-8')로 인코딩하고, 읽을 때는 base64.b64decode(field_value)로 디코딩하세요. 형식 가정이 잘못되면 파일 처리 버그가 발생하기 쉽습니다.
자주 발생하는 실수
attachment=False로 설정하면 발생하는 문제
파일을 DB 컬럼에 직접 저장하면 PostgreSQL 테이블이 빠르게 비대해집니다. 몇십 개의 PDF라도 attachment=False로 저장하면 모델 테이블이 수백 메가바이트 이상 늘어나고 모든 쿼리가 느려질 수 있습니다. 한번 이렇게 저장된 데이터를 attachment 모드로 옮기려면 별도 스크립트와 신중한 계획이 필요합니다.
파일명용 필드를 빼먹는 실수
파일명 Char 필드를 추가하지 않으면 사용자가 파일을 내려받을 때 무의미한 이름이 붙는 일이 빈번히 발생합니다. 사용자에게 완성도 낮은 구현으로 보이므로 필드를 추가하는 것은 반드시 지켜야 할 작은 체크포인트입니다.
Binary와 Image 필드 혼동
이미지 용도에 일반 Binary를 쓰면 자동 리사이즈와 썸네일 기능을 잃어 대형 이미지 업로드로 폼 로드가 느려질 수 있습니다. 반대로 PDF 같은 비이미지 파일을 fields.Image로 저장하려 하면 Odoo가 이미지로 처리하려다 오류가 납니다. 콘텐츠 유형에 맞춘 필드 선택이 중요합니다.
리스트 뷰에 Binary 필드를 직접 포함시키는 실수
리스트 뷰에 Binary 필드를 넣으면 표시되는 모든 행의 파일 내용을 불러오므로 큰 데이터 전송이 발생합니다. 목록에서 첨부 여부만 보여야 한다면 계산된 불리언 필드나 아이콘으로 대체하세요. 실무에서 데이터가 늘어나면서 성능 이슈로 드러나는 전형적인 문제입니다.
값 유무 확인을 빼먹고 처리하는 실수
값이 없는 Binary 필드는 Python에서 False를 반환합니다. 빈 문자열이나 빈 바이트가 아닙니다. 디코딩 전에 False 체크를 하지 않으면 TypeError가 발생하므로 항상 if record.x_document: data = base64.b64decode(record.x_document)처럼 보호 구문을 두어야 합니다.
맺음말
Binary 필드는 단순하지만 Odoo 데이터 모델에서 중요한 역할을 합니다. 파일·문서를 Odoo의 첨부 체계와 접근 제어 안에서 자연스럽게 관리하도록 설계된 요소입니다.
주요 습관 요약: 항상 attachment 모드를 사용하고, 파일명용 Char 필드를 함께 두며, 이미지엔 fields.Image를 사용하고, 민감 문서엔 groups로 접근을 제한하고, 코드에서 base64를 정확히 처리하세요. 이 다섯 가지를 지키면 프로덕션 환경에서 흔히 벌어지는 문제들을 사전에 예방할 수 있습니다.
Odoo Studio로 필드를 추가하든 커스텀 Python 모듈을 만들든 XML-RPC나 ORM으로 필드 생성 자동화를 하든, Binary 필드를 처음부터 올바르게 설계하면 전체 Odoo 구현이 더 깔끔하고 안정적으로 운영됩니다.
Dasolo에서는 기업이 전 부서에 걸쳐 Odoo를 도입·커스터마이즈·최적화하도록 돕습니다. 올바른 필드 타입 설계, 파일 관리 워크플로 구축, 또는 전체 모듈 개발이 필요하시면 저희 팀이 지원해드립니다. 문의하기 귀사의 Odoo 프로젝트에 대해 이야기해봅시다.