今天遇到了非常规表的创建及使用,来分享一下
使用场景:展示表用到了其他两个表的字段,并且想要对这俩表的字段进行一个操作
以下为展示表的代码
# -*- coding: utf-8 -*-
from odoo import api, models, fields, tools
class ReceiptFollowUp(models.Model):
_name = 'receipt.follow.up'
_description = '收款跟进'
_auto = False
salesman = fields.Char('业务员')
department = fields.Char('部门')
contract_no = fields.Char('合同编号')
contract_name = fields.Char('合同名称')
subordinate_company = fields.Char('所属公司')
partner_name = fields.Char('客户名称')
contract_amount = fields.Float('合同金额')
receipt_stage = fields.Char(string='收款阶段')
plan_receipt_date = fields.Date(string='计划收款日期')
stage_payback_amount = fields.Float(string='阶段回款金额')
received_amount = fields.Float('已收款金额')
unreceived_amount = fields.Float(string='未收款金额')
forecast_receipt_date = fields.Date('预测收款日期')
forecast_receipt_amount = fields.Float('预测收款金额')
submit_state = fields.Selection([('unsubmitted', '未提交'), ('submitted', '已提交')], string='提交状态')
receive_plan_id = fields.Integer('收款计划id')
def action_model_view(self):
return {
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'sales.contract',
'res_id': self.env['sales.contract'].search([('c_cust_contract_no', '=', self.contract_no)])[0].id,
}
@api.model
def btn_confirm_submission(self,select_ids):
for record in select_ids:
self_id = self.env['receipt.follow.up'].search([('id', '=', record)],limit=1)
plan_id = self.env['sales.contract.receive.plan'].search([('id', '=', self_id.receive_plan_id)],limit=1)
if plan_id:
plan_id.write({'submit_state': 'submitted'})
def init(self):
tools.drop_view_if_exists(self._cr, self._table)
self._cr.execute(f"""
CREATE OR REPLACE VIEW {self._table} AS (
SELECT
T2.id,
t1.emp_id as salesman,
t1.emp_dept_id as department,
t1.c_cust_contract_no as contract_no,
t1.proj_name as contract_name,
t1.emp_org_id as subordinate_company,
t1.c_cust_id as partner_name,
t1.pb_amount as contract_amount,
t2.receive_stage_id as receipt_stage,
t2.plan_receive_date as plan_receipt_date,
t2.stage_receive_amount as stage_payback_amount,
t2.receive_amount as received_amount,
t2.no_receive_amount as unreceived_amount,
t2.plan_receive_date as forecast_receipt_date,
t2.no_receive_amount as forecast_receipt_amount,
t2.submit_state,
t2.id as receive_plan_id
FROM sales_contract T1
INNER JOIN sales_contract_receive_plan T2 on t1."id" = t2.sales_contract_id
ORDER BY T1.id,T2.id)""")
先定义模型,注意需要设定_auto = False,这样odoo就不会自动创建表及其字段,然后字段就正常定义就好,不需要写逻辑,因为后边会用sql语句对其赋值
btn_confirm_submission为按钮调用的反写方法,直接对主表write对应内容就好了
第二步定义xml
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data>
<record id="receipt_follow_up_tree" model="ir.ui.view">
<field name="name">receipt.follow.up.tree</field>
<field name="model">receipt.follow.up</field>
<field name="arch" type="xml">
<tree create="0" limit="500" delete="false">
<field name="salesman" optional="show"/>
<field name="department" optional="show"/>
<field name="contract_no" optional="show"/>
<field name="contract_name" optional="show"/>
<field name="subordinate_company" optional="show"/>
<field name="partner_name" optional="show"/>
<field name="contract_amount" optional="show"/>
<field name="receipt_stage" optional="show"/>
<field name="plan_receipt_date" optional="show"/>
<field name="stage_payback_amount" optional="show"/>
<field name="received_amount" optional="show"/>
<field name="unreceived_amount" optional="show"/>
<field name="forecast_receipt_date" optional="show"/>
<field name="forecast_receipt_amount" optional="show"/>
<field name="submit_state" optional="show"/>
</tree>
</field>
</record>
<record id="receipt_follow_up_search" model="ir.ui.view">
<field name="model">receipt.follow.up</field>
<field name="arch" type="xml">
<search string="收款跟进">
<field name="salesman"/>
<field name="department"/>
<field name="contract_no"/>
<field name="contract_name"/>
</search>
</field>
</record>
<!--窗口动作-->
<record id="receipt_follow_up_action" model="ir.actions.act_window">
<field name="name">收款跟进</field>
<field name="res_model">receipt.follow.up</field>
<field name="view_mode">tree</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">创建您的收款跟进</p>
</field>
</record>
<menuitem id="receipt_follow_up_menu" name="收款跟进" parent="payback_forecast_menu" sequence="1"
action="receipt_follow_up_action"/>
</data>
</odoo>
定义tree,search视图,action及menuitem,与正常表无差别
还有一种情况就是反写的内容不是固定的可怎么办呢:
可以在tree视图最后增加button来调用后端方法
效果如下
def btn_operation_update(self):
"""
收款变更按钮
:return:
"""
return {
'name': '收款变更',
'type': 'ir.actions.act_window',
'res_model': 'receipt.change.transient',
'view_mode': 'form',
'target': 'new',
'context': {'forecast_receipt_date': self.forecast_receipt_date, 'forecast_receipt_amount': self.forecast_receipt_amount,
'receive_plan_id': self.receive_plan_id}
}
后端方法来返回一个transient模型的form视图,transient模型是用来计算值的中间表,context中可以传入现在状态的一些数据,注意他不储存数据,只能用这些数据来计算并返回,下面是我定义的transient模型
from odoo import models, fields
from odoo.exceptions import ValidationError
class ReceiptChangeTransient(models.TransientModel):
_name = 'receipt.change.transient'
_description = '收款变更 transient'
forecast_receipt_date = fields.Date('预测收款日期')
forecast_receipt_amount = fields.Float('预测收款金额')
def confirm_change(self):
receive_plan_id = self._context.get('receive_plan_id')
plan_id = self.env['sales.contract.receive.plan'].search([('id', '=', receive_plan_id)], limit=1)
if plan_id:
plan_id.write({'plan_receive_date': self.forecast_receipt_date,
'no_receive_amount': self.forecast_receipt_amount})
else:
raise ValidationError('没有找到对应的收款计划!')
我只需要计算两个字段,所以只定义了这两个字段,confirm_change是确认按钮的方法,来实现回写,下面是transient模型的form视图
<?xml version='1.0' encoding='utf-8'?>
<odoo>
<data noupdate="0">
<record id="receipt_change_transient_form_view" model="ir.ui.view">
<field name="name">收款变更wizard</field>
<field name="model">receipt.change.transient</field>
<field name="arch" type="xml">
<form style="text-align: center">
<sheet>
<group>
<group>
<field name='forecast_receipt_date' string='预测收款日期'/>
</group>
<group>
<field name='forecast_receipt_amount' string='预测收款金额'/>
</group>
</group>
<footer>
<button string="确认变更" name="confirm_change" type="object" class="btn btn-primary"/>
<button string="取消" class="btn btn-default" special="cancel"/>
</footer>
</sheet>
</form>
</field>
</record>
</data>
</odoo>
确认变更按钮来调用后端的confirm_change来实现回写逻辑,效果如下:
点击确认变更按钮效果如下,可以发现这俩字段的值已经变了,说明主表的这俩字段已经回写成功(这里其实就是主表的字段,只是用来展示)
至此结束
views表解释:
在Odoo中,模型(Model)在数据库中通常被映射为表(Table),而不是视图(View)。模型对应的表用于存储与模型相关的数据,包括模型定义的字段和相关记录。
然而,有时候会有一些特殊情况,某些模型在数据库中会被映射为views
表,而不是实际的数据表。这通常发生在具有动态或计算字段的模型上。
当一个模型定义了动态或计算字段时,这些字段的值是根据其他字段的计算结果动态生成的,而不是直接存储在数据库中。因此,对于这些模型,不需要在数据库中创建对应的数据表来存储字段的值。
相反,这些模型的数据是通过视图(View)来呈现和计算的。这些视图定义了模型字段的计算逻辑和展示方式,以及如何将数据显示给用户。这些视图在运行时根据模型的定义动态生成,并在访问模型数据时执行相应的计算。
所以,当一个模型在数据库中被映射为views
表时,它表示该模型的数据是通过视图计算和呈现的,而不是存储在实际的数据表中。这种做法使得可以在不存储实际字段值的情况下,动态地计算和展示数据,并在需要时提供准确的计算结果。