You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Odoo 15.0 res.partner继承问题求助:Student模型字段与视图异常

Odoo 15.0 Student模型与res.partner关联问题解决方案

问题背景

开发Student模型时,希望复用res.partner中的name、phone、email等字段,过程中遭遇多轮异常,最终改用Many2one关联方式后,视图仍无法正常工作。


第一次尝试:直接继承res.partner

最初通过_inherit直接继承res.partner,代码如下:

from odoo import models, fields, api

class Student(models.Model):
    _name = 'student'
    _inherit = 'res.partner'
    _description = 'Model to manage school students'

    registration_ids = fields.One2many('registration', 'student_id', string='Registration')
    student_DNI = fields.Integer(string='ID')
    course_id = fields.Many2one('course', string='Course')
    birth_date = fields.Date(string='Birth Date')
    age = fields.Integer(string='Age', compute='_compute_age', store=True)

    @api.depends('birth_date')
    def _compute_age(self):     
        for student in self:         
            if student.birth_date:              
                today = fields.Date.today()              
                student.age = today.year - student.birth_date.year         
            else:              
                student.age = 0

触发错误:

TypeError: Many2many fields student.channel_ids and res.partner.channel_ids use the same table and columns


第二次修改:自定义邮件频道字段

为解决字段冲突,在Student模型中重定义channel_ids:

student_channel_ids = fields.Many2many(
    'mail.channel', 
    relation='student_mail_channel_rel', 
    column1='student_id', 
    column2='channel_id', 
    string='Channels'
)

再次触发数据库错误(西班牙语提示):

psycopg2.errors.DuplicateColumn: ya existe la columna «signup_token» en la relación «res_partner»
(翻译:res_partner表中已存在signup_token列)


第三次调整:改用Many2one关联res.partner

放弃继承,改用Many2one字段关联res.partner,最终模型代码:

from odoo import models, fields, api

class Student(models.Model):
    _name = 'student'
    _description = 'Model to manage school students'
    partner_id = fields.Many2one('res.partner', string='Partner', required=True, ondelete="cascade")
    registration_ids = fields.One2many('registration', 'student_id', string='Registration')
    student_DNI = fields.Integer(string='ID')
    course_id = fields.Many2one('course', string='Course')
    birth_date = fields.Date(string='Birth Date')
    age = fields.Integer(string='Age', compute='_compute_age', store=True)

    @api.depends('birth_date')
    def _compute_age(self):     
        for student in self:         
            if student.birth_date:              
                today = fields.Date.today()              
                student.age = today.year - student.birth_date.year         
            else:              
                student.age = 0

视图代码:

<odoo>
    <data>
        <record model="ir.ui.view" id="view_student_form">
            <field name="name">student.form</field>
            <field name="model">student</field>
            <field name="inherit_id" ref="base.view_partner_form"/>
            <field name="arch" type="xml">
            <form> 
                <xpath expr="//field[@name='email']" position="after">
                    <field name="birth_date"/>
                    <field name="age"/>
                    <field name="student_DNI"/>
                    <field name="course_id"/>
                </xpath>
            </form>
            </field>
        </record>
    </data>
</odoo>

此时视图无法正常渲染,且字段复用逻辑存疑。


解决方案

方案一:修复直接继承res.partner的问题

  1. 解决channel_ids冲突:
    在Student模型中重定义channel_ids,指定独立关联表:
    channel_ids = fields.Many2many(
        'mail.channel',
        'student_mail_channel_rel',
        'student_id',
        'channel_id',
        string='Channels'
    )
    
  2. 解决signup_token重复问题:
    • 测试环境可卸载模块后清理数据库残留字段
    • 若需邮件功能,添加多继承确保字段逻辑正确:
      _inherit = ['res.partner', 'mail.thread']
      

方案二:修复Many2one关联下的视图问题

当前视图错误在于继承了res.partner的视图,但模型为student,两者不匹配。可通过两种方式修复:

1. 创建独立Student视图

直接编写视图,通过widget嵌套显示res.partner字段:

<odoo>
    <data>
        <record model="ir.ui.view" id="view_student_form">
            <field name="name">student.form</field>
            <field name="model">student</field>
            <field name="arch" type="xml">
                <form>
                    <sheet>
                        <group>
                            <!-- 嵌套显示res.partner字段 -->
                            <field name="partner_id" string="Partner Details" widget="form" readonly="False">
                                <form>
                                    <field name="name"/>
                                    <field name="phone"/>
                                    <field name="email"/>
                                </form>
                            </field>
                            <!-- Student自有字段 -->
                            <field name="birth_date"/>
                            <field name="age"/>
                            <field name="student_DNI"/>
                            <field name="course_id"/>
                        </group>
                        <notebook>
                            <page string="Registrations">
                                <field name="registration_ids"/>
                            </page>
                        </notebook>
                    </sheet>
                </form>
            </field>
        </record>

        <!-- 注册菜单与动作 -->
        <record model="ir.actions.act_window" id="action_student">
            <field name="name">Students</field>
            <field name="res_model">student</field>
            <field name="view_mode">tree,form</field>
        </record>
        <menuitem name="Students" id="menu_student" parent="base.menu_partner" action="action_student"/>
    </data>
</odoo>

2. 使用委托继承(推荐)

通过_inherits实现字段自动复用,同时避免继承冲突:

class Student(models.Model):
    _name = 'student'
    _inherits = {'res.partner': 'partner_id'}
    _description = 'Model to manage school students'

    partner_id = fields.Many2one('res.partner', string='Partner', required=True, ondelete="cascade")
    registration_ids = fields.One2many('registration', 'student_id', string='Registration')
    student_DNI = fields.Integer(string='ID')
    course_id = fields.Many2one('course', string='Course')
    birth_date = fields.Date(string='Birth Date')
    age = fields.Integer(string='Age', compute='_compute_age', store=True)

    # 重定义channel_ids避免冲突
    channel_ids = fields.Many2many(
        'mail.channel',
        'student_mail_channel_rel',
        'student_id',
        'channel_id',
        string='Channels'
    )

    @api.depends('birth_date')
    def _compute_age(self):     
        for student in self:         
            if student.birth_date:              
                today = fields.Date.today()              
                student.age = today.year - student.birth_date.year         
            else:              
                student.age = 0

此时视图可直接继承res.partner的表单视图:

<odoo>
    <data>
        <record model="ir.ui.view" id="view_student_form">
            <field name="name">student.form</field>
            <field name="model">student</field>
            <field name="inherit_id" ref="base.view_partner_form"/>
            <field name="arch" type="xml">
                <xpath expr="//field[@name='email']" position="after">
                    <field name="birth_date"/>
                    <field name="age"/>
                    <field name="student_DNI"/>
                    <field name="course_id"/>
                </xpath>
            </field>
        </record>
    </data>
</odoo>

内容的提问来源于stack exchange,提问作者Alex Aguirre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 17:57:10