Usage Patterns
- To display external image URLs within a Form view, utilize an
Htmltype computed field that returns the image markup. - Pay close attention to the declaration order within the
__init__method when extending models to ensure proper initialization.
System Configuration
Extend res.config.settings to manage system parameters. By assigning the config_parameter attribute to a field, the setting is stored directly in the system parameters table.
class ConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
api_key = fields.Char(
string='API Key',
config_parameter='my_custom.api_key',
default=''
)
shared_secret = fields.Char(
string='Shared Secret',
config_parameter='my_custom.shared_secret',
default=''
)
Note: Since res.config.settings is a Transient model, records are not permanently stored in the database table. To persist data related to other models, use related fields.
Installation and Deployment
Installing Odoo 17 from Source on CentOS
Environment: CentOS, 2 vCPUs, 8GB RAM.
mkdir -p /var/www/odoo
cd /var/www/odoo
git clone -b 17.0 --depth=1 https://github.com/odoo/odoo.git server
mkdir -p custom/addons
# Install Python 3.11 and dependencies
yum install python3.11 python3.11-devel
pip3.11 install -r server/requirements.txt
# Start the server
python3.11 server/odoo-bin -c /etc/odoo/odoo.conf &
# Stop the server
pkill -f odoo-bin
Database Configuration
yum install postgresql-server
systemctl enable postgresql
systemctl start postgresql
postgresql-setup initdb
# Configure pg_hba.conf for md5 authentication
# Configure postgresql.conf to listen on '*'
Odoo Configuration File (odoo.conf)
[options]
addons_path = /var/www/odoo/server/addons,/var/www/odoo/custom/addons
admin_passwd = admin_secure_password
data_dir = /var/lib/odoo
logfile = /var/log/odoo/odoo.log
log_level = info
# Database Settings
db_host = False
db_port = 5432
db_user = odoo
db_password = strong_password
# Resource Limits
limit_memory_soft = 2147483648
limit_memory_hard = 2684354560
limit_time_cpu = 60
limit_time_real = 120
Troubleshooting python-ldap Installation
Errors regarding missing Python.h typically indicate missing development headers. Install the necessary development tools:
yum groupinstall "Development tools"
yum install openldap-devel python3.11-devel
Common Issues and Solutions
- HTML Field Rendering: String concatenation for HTML fields may not render correctly (e.g.,
r.html = '<b>A</b>' + r.html2). Use Python f-strings to ensure proper interpretation:r.html = f'<b>A</b>{r.html2}'. - Group Visibility: Custom access groups categorized under 'Human Resources' may not appear without developer mode enabled. Ensure the
ir.module.categoryrecord defines the correct hierarchy and sequence.
Error Handling
- Startup Failure after Extension: If adding fields to
res.partnerprevents startup, force an update using the-u module_namecommand line argument. Alternatively, comment out the new fields, restart, update the module via the UI, uncomment the code, and restart again. - AttributeError in Dependencies: An error like
'Integer' object has no attribute 'split'often indicates missing quotes around field names in an@api.dependsdecorator. - Domain Syntax Errors: A
TypeErrorregarding subscriptable integers usually stems from incorrect domain tuple formatting (e.g., missing parentheses). - Module Compatibility:
AttributeError: module 'lib' has no attribute 'OpenSSL_add_all_algorithms'suggests a conflict betweencryptographyandpyopenssl. Downgradingcryptographyoften resolves this:pip install cryptography==38.0.4.
Security Checklist
- If menus or records are not visible despite being defined, verify that the
security/ir.model.access.csvfile is present and correctly populated with ACL rules. - For Odoo 17 development, strictly use Python 3.11, as Python 3.12 may cause dependency installation failures.
Frontend Development Tips
When invoking a parent method within a callback context, ensure the context is bound correctly before invocation.
// Correctly binding _super for later execution
var parentMethod = this._super.bind(this, ...arguments);
this._performAsyncCheck().then((result) => {
if (result) {
return parentMethod();
}
}).catch((error) => {
Dialog.alert(this, error.message || _t("Operation Failed"));
});
Avoid using this._super.apply(this, arguments) in methods that do not actually inherit from a parent, as this will result in an undefined reference.