当前位置:首页>python>中篇Python(ODOO)篇 第三章 ODOO项目开发(三)添加基础部分模块 7.学员管理

中篇Python(ODOO)篇 第三章 ODOO项目开发(三)添加基础部分模块 7.学员管理

  • 2026-10-11 08:33:19
中篇Python(ODOO)篇 第三章 ODOO项目开发(三)添加基础部分模块 7.学员管理
原始需求:

会员编号:

自动编号

姓名:

王小二

性别:

男

出生年月日:

1974/05/11

注册时间:

2010/1/11

驾照类型:

C1

驾照号码:

23232232

住宅电话:

11111

住宅地址:

上海浦东大道1111号

职业:

商务及销售行业

邮政编码:

434300

单位名称:

宝钢大厦

单位地址:

上海浦东大道22号

单位电话:

22222

传真:

2222

手机号码

1862323

电子邮件:

23@qq.com

该子模块主要是客户使用,需要给group_peijia_user权限组赋权。
另外,会员编号是自动编号。

新增数据模型

models目录新建student.py数据模型文件,代码如下:
# -*- coding: utf-8 -*-from odoo import fields, models, apiclass NebulaStudent(models.Model):    _name = "nebula.student"    _description = "学员管理"    _order = 'seq desc, name'    seq = fields.Char('学员编号', size=20, readonly=True)  # 自动编号所以只读    name = fields.Char('姓名', size=20, required=True, copy=False,                       index=True, default='无名氏')    sex = fields.Selection([('M', '男'), ('F', '女'), ],                           default='M', string='性别')    birthday = fields.Date('出生年月日', copy=False)    id_card = fields.Char('身份证', size=20, copy=False)    mobile = fields.Char('手机号码', size=40, copy=False)    driving_licence_type_name = fields.Selection(selection='_select_driving_licence_type',                                                 string='驾照类型')    driving_licence_number = fields.Char('驾照号码', size=30, required=True, default='请输入')    driving_licence_birthday = fields.Date("驾照领取日期")    work_name = fields.Char('单位名称')    work_tel = fields.Char('单位电话', size=100)    work_address = fields.Text('单位地址')    fax = fields.Char('传真', size=100)    metier_type_name = fields.Selection(selection='_select_metier_type', string='职业类型')    mail = fields.Char('电子邮件', size=30, copy=False)    home_address = fields.Text(string='家庭地址', copy=False)    home_tel = fields.Char(string='家庭电话', size=100, copy=False)    note = fields.Text('备注', copy=False)    @api.model    def _select_metier_type(self):        records = self.env['nebula.metier.type'].search([('active', '=', True)])        return [(r.name, r.name) for r in records]    def _select_driving_licence_type(self):        records = self.env['nebula.driving.licence.type'].search([('active', '=', True)])        return [(r.name, (r.name + '(' + r.name_type + ')')) for r in records]
将该文件名添加到models目录下__init__.py文件中,之前已经有演示。

设置访问权限

在security目录下的ir.model.access.csv新增两行权限记录。
access_nebula_student_manager,nebula.student,model_nebula_student,group_peijia_manager,1,1,1,1access_nebula_student_user,nebula.student,model_nebula_student,group_peijia_user,1,1,1,0

创建视图层

在views目录新增student_views.xml文件,先用默认方式展示即可,待模块加载成功后再逐步修改和完善文件,内容如下:
<?xml version="1.0" encoding="utf-8"?><odoo>    <act_windowid="peijia.action_student_views"name="学员管理"    res_model="nebula.student" view_mode="tree,form" /></odoo>
修改peijia目录下__manifest__.py文件中data段,在views/car_type_views.xml前新增views/student_views.xml文件名。
在views目录下car_views.xml文件,在二级菜单基础资料下方添加新的二级菜单学员,代码:
<  menuitemid="menu_peijia_student_data"name="学员"sequence="20"parent="menu_peijia_root"/>
截图:
在views目录下car_views.xml文件,前添加菜单指向学员管理子模块,代码:
<  menuitemid="menu_student_views"name="学员管理"parent="menu_peijia_student_data"sequence="100"action="peijia.action_student_views"/>
截图:
重启后,更新陪驾模块,查看是否已经有相关菜单和界面。正常后继续修改视图层。

测试用户权限

现在我们测试以下之前设置的user权限组是不是正常,该组没有删除权限。
为简单起见,先进入开发模式,然后选择设置菜单,再选择用户,选择新增用户,添加一个pjuser@163.com的用户,并设置在陪驾模块为User组,点击保存按钮保存该用户。

点击动作菜单的修改密码,点击pjuser@163.com,将密码修改为123456。

点击右上角当前登录用户,点击登出,
在登录窗口输入用户:pjuser@163.com,密码:123456,点击登录。
点击汽车陪驾模块。
提示驾照类型没有权限,
因为学员管理里面有驾照类型和职业类型,所以我们需要给这两个模块只读权限。
在ir.model.access.csv中给User组权限。
保存,并用管理员账号更新陪驾应用,再用pjuser@163.com账号登录,发现基础菜单和学员管理菜单都有了,学员管理菜单没有删除菜单可使用。

完善视图层

将teacher_views.xml文件中act_window段删除,修改如下:
<?xml version="1.0" encoding="utf-8"?><odoo>    <data>        <recordmodel="ir.ui.view"id="peijia.action_form_student_views">            <fieldname="name">peijia.student.form</field>            <fieldname="model">nebula.student</field>            <fieldname="arch"type="xml">                <formstring="表单">                    <sheet>                        <divclass="oe_button_box"name="button_box">                        </div>                        <groupname="group_top">                            <groupname="group_left">                                <fieldname="seq"/>                                <fieldname="name"/>                                <fieldname="sex"/>                                <fieldname="birthday"/>                            </group>                            <groupname="group_right">                                <fieldname="mobile"/>                            </group>                        </group>                        <notebookcolspan="4">                            <pagestring="单位信息"autofocus="autofocus">                                <group>                                    <fieldname="work_name"/>                                    <fieldname="work_tel"/>                                    <fieldname="work_address"/>                                    <fieldname="fax"/>                                    <fieldname="metier_type_name"/>                                    <fieldname="mail"/>                                    <fieldname="driving_licence_type_name"/>                                    <fieldname="driving_licence_number"/>                                    <fieldname="driving_licence_birthday"/>                                </group>                            </page>                            <pagestring="个人信息">                                <group>                                    <fieldname="id_card"/>                                    <fieldname="note"/>                                </group>                            </page>                            <pagestring="家庭信息">                                <group>                                    <fieldname="home_address"/>                                    <fieldname="home_tel"/>                                </group>                            </page>                        </notebook>                    </sheet>                </form>            </field>        </record>        <recordmodel="ir.ui.view"id="peijia.search_student_views">            <fieldname="name">peijia.student.search</field>            <fieldname="model">nebula.student</field>            <fieldname="arch"type="xml">                <search>                    <fieldname="seq"/>                    <fieldname="name"/>                    <fieldname="mobile"/>                </search>            </field>        </record>        <recordmodel="ir.ui.view"id="peijia.action_tree_student_views">            <fieldname="name">peijia.student.tree</field>            <fieldname="model">nebula.student</field>            <fieldname="priority">1</field>            <fieldname="arch"type="xml">                <treestring="列表">                    <fieldname="seq"/>                    <fieldname="name"/>                    <fieldname="sex"/>                    <fieldname="mobile"/>                </tree>            </field>        </record>        <recordmodel="ir.actions.act_window"id="peijia.action_student_views">            <fieldname="name">学员管理</field>            <fieldname="type">ir.actions.act_window</field>            <fieldname="res_model">nebula.student</field>            <fieldname="view_mode">tree,form</field>        </record>    </data></odoo>

创建自动编号

在data目录新增student_seq_data.xml文件,用来存放编号定义文件。代码如下:
<?xml version="1.0" encoding="utf-8"?><odoo>    <datanoupdate="1">        <recordid="seq_student_apply"model="ir.sequence">            <fieldname="name">学员编号</field>            <fieldname="code">nebula.student.seq</field>            <fieldname="prefix">ST%(year)s%(month)s%(day)s</field>            <fieldname="padding">3</field>        </record>    </data></odoo>
注:
ST是前缀%(year)s表示年,month是月,day是日padding 3表示序列号是几位宽度的,3表示从001到999
如果2020年4月3日第一笔单据,则学员编号是ST20200403001。
我们在__manifest__.py文件中data段和默认数据一样在最后添加该文件位置,以方便调用。
格式如下:data/student_seq_data.xml
修改student.py文件,在class NebulaStudent最后部分,添加以下代码:
@api.modeldef create(self, vals):    if vals.get('seq', _('New')) == _('New'):        vals['seq'] = self.env['ir.sequence'].next_by_code('nebula.student.seq')    return super(NebulaStudent, self).create(vals)
该语句意思是在创建保存的时候,查看seq字段的值是不是“新建”,如果是则将获取自动序号。
_(‘New’)的值,odoo会自动根据语言等信息获取对应的文本,中文是“新建”。
同时需要在student.py文件导入_,代码如下:
from odoo import fields, models, api, _
修改class NebulaStudent的seq字段定义,添加默认字段,代码如下:
seq = fields.Char('学员编号', default=lambda self: _('New'),                  copy=False, readonly=True)  # 自动编号所以只读
student.py完整代码:
# -*- coding: utf-8 -*-from odoo import fields, models, api, _class NebulaStudent(models.Model):    _name = "nebula.student"    _description = "学员管理"    _order = 'seq desc, name'    seq = fields.Char('学员编号', default=lambda self: _('New'),                      copy=False, readonly=True)  # 自动编号所以只读    name = fields.Char('姓名', size=20, required=True, copy=False,                       index=True, default='无名氏')    sex = fields.Selection([('M', '男'), ('F', '女'), ],                           default='M', string='性别')    birthday = fields.Date('出生年月日', copy=False)    id_card = fields.Char('身份证', size=20, copy=False)    mobile = fields.Char('手机号码', size=40, copy=False)    driving_licence_type_name = fields.Selection(selection='_select_driving_licence_type',                                                 string='驾照类型')    driving_licence_number = fields.Char('驾照号码', size=30, required=True, default='请输入')    driving_licence_birthday = fields.Date("驾照领取日期")    work_name = fields.Char('单位名称')    work_tel = fields.Char('单位电话', size=100)    work_address = fields.Text('单位地址')    fax = fields.Char('传真', size=100)    metier_type_name = fields.Selection(selection='_select_metier_type', string='职业类型')    mail = fields.Char('电子邮件', size=30, copy=False)    home_address = fields.Text(string='家庭地址', copy=False)    home_tel = fields.Char(string='家庭电话', size=100, copy=False)    note = fields.Text('备注', copy=False)    @api.model    def _select_metier_type(self):        records = self.env['nebula.metier.type'].search([('active', '=', True)])        return [(r.name, r.name) for r in records]    def _select_driving_licence_type(self):        records = self.env['nebula.driving.licence.type'].search([('active', '=', True)])        return [(r.name, (r.name + '(' + r.name_type + ')')) for r in records]    @api.model    def create(self, vals):        if vals.get('seq', _('New')) == _('New'):            vals['seq'] = self.env['ir.sequence'].next_by_code('nebula.student.seq')        return super(NebulaStudent, self).create(vals)

重启升级,新增一条学员可看到效果。

界面展示

列表效果:
表单效果:

最新文章

随机文章