在 Odoo 中,确实可以通过 SQL 语句来提升一些功能逻辑的处理效率。将 SQL 转为 Python 代码,并在 Odoo 模块中使用,可以通过以下几种方式实现。
1. 使用 env.cr.execute
执行 SQL 语句
Odoo ORM 提供的 env.cr.execute()
可以直接执行 SQL 语句,这样可以在 Python 代码中调用 SQL 逻辑,结合 Odoo 的业务模型实现复杂的逻辑操作。execute()
方法适合处理批量数据更新、复杂查询等。
示例:批量更新 customer_id
字段
def update_customer_ids(self): query = """ UPDATE purchase_account_invoice AS pai SET customer_id = COALESCE( (SELECT delivery_order.customer_id FROM delivery_order WHERE delivery_order.id = pai.delivery_order_id), (SELECT purchase_order.customer_id FROM purchase_order WHERE purchase_order.id = pai.purchase_order) ) WHERE pai.delivery_order_id IS NOT NULL OR pai.purchase_order IS NOT NULL; """ self.env.cr.execute(query) self.env.cr.commit() # 提交更改
注意:SQL 操作后,可以用 invalidate_cache()
来刷新缓存,确保 ORM 缓存数据一致
2. 使用 SQL 函数实现数据聚合或计算
在 Odoo 中处理数据聚合、统计和复杂计算时,可以用 SQL 函数(如 SUM
、COUNT
、AVG
等)直接在数据库中完成计算,减少了 Python 循环操作,能大幅提高效率。
示例:统计每位客户的总订单金额
def get_total_order_amount_by_customer(self): query = """ SELECT partner_id, SUM(amount_total) FROM sale_order GROUP BY partner_id """ self.env.cr.execute(query) results = self.env.cr.fetchall() # 处理查询结果 for partner_id, total_amount in results: print(f"客户ID: {partner_id}, 总订单金额: {total_amount}")
3. 使用 env.cr.fetchall()
获取 SQL 查询结果
fetchall()
方法可以将 SQL 查询结果作为列表返回,适用于需要将查询结果进一步处理的情况。对于复杂的查询结构,fetchall()
提供了一个非常方便的方式将数据转化为 Python 可用的格式。
示例:筛选满足特定条件的订单
def get_filtered_orders(self): query = """ SELECT id, name, amount_total FROM sale_order WHERE state = 'sale' AND amount_total > 5000 """ self.env.cr.execute(query) results = self.env.cr.fetchall() return [{'id': row[0], 'name': row[1], 'amount_total': row[2]} for row in results]
4. 使用 WITH
语句和 SQL CTE(公用表表达式)
对于需要多层嵌套查询的复杂 SQL 逻辑,可以使用 WITH
语句创建临时表,然后在 Python 代码中使用 env.cr.execute()
来执行。CTE 非常适合处理复杂的条件筛选、分组和聚合查询。
示例:计算每月的销售总额
def get_monthly_sales(self): query = """ WITH monthly_sales AS ( SELECT DATE_TRUNC('month', order_date) AS month, SUM(amount_total) AS total FROM sale_order WHERE state = 'sale' GROUP BY DATE_TRUNC('month', order_date) ) SELECT month, total FROM monthly_sales ORDER BY month; """ self.env.cr.execute(query) results = self.env.cr.fetchall() return [{'month': row[0], 'total': row[1]} for row in results]
5. 使用 Odoo ORM 结合 SQL 优化批量操作
在某些情况下,将 Odoo ORM 的便利性和 SQL 的高效性结合使用,可以优化批量操作。比如在进行多条数据筛选和更新时,可以用 ORM 的 search
查找到所需的记录,然后用 SQL 批量更新,既保持了 ORM 的兼容性,也享受了 SQL 的效率。
示例:更新符合条件的记录,避免逐条写入
def update_large_records(self): record_ids = self.env['purchase.account.invoice'].search([]).ids if record_ids: query = """ UPDATE purchase_account_invoice SET customer_id = 1 -- 假设所有满足条件的记录的 customer_id 更新为 1 WHERE id = ANY(%s) """ self.env.cr.execute(query, (record_ids,)) self.env.cr.commit()
6. 在 @api.model
或 @api.multi
方法中结合 SQL 执行业务逻辑
在自定义模型方法中,可以使用 SQL 来执行业务逻辑,并返回结构化数据,进一步结合 ORM 实现功能。
示例:在自定义按钮操作中批量执行 SQL 操作
from odoo import models, api class PurchaseAccountInvoice(models.Model): _name = 'purchase.account.invoice' @api.multi def action_bulk_update(self): for record in self: query = """ UPDATE purchase_account_invoice SET customer_id = %s WHERE id = %s """ self.env.cr.execute(query, (record.new_customer_id, record.id)) self.env.cr.commit()
总结
env.cr.execute()
:在 Odoo 中执行 SQL 语句的核心方法,适用于批量操作和复杂查询。- 结合 SQL 函数:通过 SQL 中的聚合函数如
SUM
、COUNT
等,实现高效的数据统计。 fetchall()
返回结果:配合execute()
使用,将查询结果处理为 Python 的数据格式。WITH
语句和 CTE:用于多层嵌套查询和复杂的 SQL 逻辑处理。- SQL 和 ORM 结合:对于批量数据更新,将 Odoo ORM 的便利性和 SQL 的高效性结合,可以获得最佳性能。
这种结合 SQL 与 Python 代码的方式,不仅能提升代码效率,还能简化业务逻辑。