Hệ thống đã production-ready. Câu hỏi cuối, và là câu quan trọng nhất: khi ổ cứng hỏng, bạn phục hồi được không? Nhiều người pg_dump cơ sở dữ liệu, thấy file backup nằm đó, rồi yên tâm. Đó là một cái bẫy chết người — vì một nửa dữ liệu của Odoo không nằm trong CSDL. Bài này chỉ ra chỗ nửa còn lại nằm, cách backup/restore đúng, và khung migration script để nâng cấp schema an toàn.
Hai phần của một backup Odoo
Dữ liệu Odoo chia làm hai nơi:
- Cơ sở dữ liệu (PostgreSQL): bảng, bản ghi, cấu hình. Backup bằng
pg_dump. - Filestore: một thư mục chứa attachment và ảnh (
ir.attachmentlớn được lưu ra file thay vì nhét vào CSDL để bảng không phình). Nằm ở/var/lib/odoo/filestore/<db>.
Thiếu một trong hai là phục hồi hỏng: có CSDL mà mất filestore thì mọi ảnh/tệp thành liên kết chết. Đây không phải lý thuyết — đo thật trên blog19:

Hình 1: Thật. pg_dump -Fc cho file 10.5 MB (đã nén), mục lục 17.189 dòng — đọc bằng pg_restore --list thấy đủ bảng module quan_the_thanh_vien, quan_lich_su_diem, quan_uu_dai. Nhưng filestore là 65 MB, 542 tệp — gấp 6 lần dump CSDL. Đây là toàn bộ ảnh/attachment, nằm ngoài CSDL. Backup mà quên nó thì phục hồi lên là ảnh vỡ hết.
Script backup và restore
Backup đúng là hai lệnh, restore là ba:

Hình 2: Backup gồm pg_dump -Fc (định dạng custom, nén sẵn, restore chọn lọc được) và tar filestore. Restore: createdb + pg_restore + giải nén filestore về đúng chỗ. Nếu chỉ cần một lệnh, giao diện /web/database/backup của Odoo xuất một file zip gồm cả hai — tiện cho backup thủ công, nhưng script pg_dump hợp cho lịch tự động vì không giữ nguyên cả DB trong RAM.
-Fc hay -Fp
pg_dump có hai định dạng hay dùng:
-Fc(custom): nhị phân, nén sẵn, vàpg_restorecho phép chọn lọc (khôi phục riêng vài bảng, đổi thứ tự, chạy song song). Đây là lựa chọn mặc định cho production.-Fp(plain): file SQL text thuần, đọc được bằng mắt, restore bằngpsql. Hợp khi cần xem/sửa nội dung dump, nhưng không nén và không chọn lọc được.
Migration: khi schema đổi
Backup lo dữ liệu; migration lo việc đổi cấu trúc giữa các phiên bản module mà không mất dữ liệu cũ. Khi bạn -u một module có version mới hơn, Odoo tự tìm thư mục migrations/<version>/ và chạy các script trong đó:
pre-migrate.py: chạy trước khi Odoo cập nhật schema — dùng khi cần giữ dữ liệu trước lúc cột bị đổi/xoá.post-migrate.py: chạy sau khi schema đã cập nhật — dùng để điền dữ liệu cho cột mới, chuyển đổi giá trị.
Mỗi script có hàm migrate(cr, version): cr là con trỏ CSDL để chạy SQL trực tiếp, version là phiên bản cũ (rỗng nếu cài mới — thường return ngay). Thư viện openupgradelib cung cấp nhiều hàm tiện ích (đổi tên cột, gộp bản ghi) cho migration phức tạp.
# migrations/19.0.2.0.0/post-migrate.py
def migrate(cr, version):
if not version: # cài mới, không cần migrate
return
cr.execute("UPDATE quan_the_thanh_vien SET hang_the='bac' "
"WHERE hang_the IS NULL") # điền mặc định cho cột cũ
Neutralize khi copy prod sang test
Một cái bẫy vận hành: khi bê backup production về máy test, đừng chạy nguyên. Bản sao vẫn giữ cron (có thể gửi email thật cho khách!), API key, cấu hình thanh toán thật. Odoo có bước neutralize (/web/database hoặc --load=...) tắt cron, chuyển mail sang chế độ không gửi, vô hiệu API key — chạy nó ngay sau khi restore lên môi trường không phải production.
Ba ý mang về
- Backup Odoo = CSDL + filestore, thiếu một là hỏng. Đo thật: dump CSDL 10.5 MB nhưng filestore 65 MB (542 tệp) — gấp 6 lần. Filestore chứa attachment/ảnh nằm ngoài CSDL.
pg_dump -Fc(nén, restore chọn lọc) cho production; restore làcreatedb+pg_restore+ đặt lại filestore. Giao diện/web/database/backupxuất zip gồm cả hai cho backup thủ công.- Migration đổi schema an toàn qua
migrations/<version>/pre|post-migrate.pyvới hàmmigrate(cr, version); và neutralize bản sao trước khi chạy ngoài production để không gửi mail/gọi API thật.
Ta vừa lướt qua migration script — nhưng đây là chủ đề đủ sâu để mổ xẻ riêng. Phần sau đi vào chi tiết pre/post/end script khi nâng cấp: thứ tự chạy chính xác, khi nào dùng cái nào, và các hàm openupgradelib hay dùng nhất.