第二章:odoo12 搭建第一个应用

odoo遵循了MVC模式model、controllers、view
1、在odoo目录下同与‘addons’同级目录创建一个例如“custom_addons”模块用于存放自己开发的模块;
在这里插入图片描述
2、在‘odoo.conf’文件中配置文件路径,便于加载:
在这里插入图片描述
3、创建项目目录和声明文件:

python3 odoo-bin scaffold 创建的模块名 模块放置的目录
# 例如 
python3 odoo-bin scaffold library_app custom_addons

如下图创建完会生成如下图的项目目录:
在这里插入图片描述
4、对_manifest_.py文件进行相关配置:
在这里插入图片描述
主要配置红色标记的便于在‘应用中’搜索到;
manifest.py’文件中的字段说明:

	name : 插件模块标题字符串;
	description : 功能描述长文件,通常为RST格式;此处可由模块目录下的README.rst或者README.md代替。
	author : 作者姓名,此处为一个字符串,如有多个作者可以用逗号分隔;
	depends :该模块所依赖的插件模块列表,在创建的时候回自动添加内核base模块,注意所有依赖的模块都需要在此处声明,否则会因为找
			  不到相应模块而报错; 
	summary :显示为模块副标题的字符串;
	version :版本号;
	license :默认为LGPL-3;
	website :关于模块信息的URL;
	category :模块功能性分类的字符串;
	data : 声明视图和权限文件,注意一般权限文件需要放在视图前面,避免引起关于ID找不到的现象;
# ###########################################注意##########################################
	application :布尔型标记,代表模块是在应用列表中以APP展现;
	installable :默认为True,但可以通过设置为False来禁用模块;
	auto_install :若设置为True,在其依赖已安装时会自动安装,主要用于同一个实例两个模块安装后功能的链接。

5、添加图标:
图标可在该网址选择:https://www.iconfont.cn/home/index
①、在项目目录下创建如下目录“static/description”将对象的图标放置在description目录下;
6、去应用中查看模块:
①、激活开发者模式,url中就会有debug=#:
在这里插入图片描述
②、点击“刷新本地模块列表”在搜索框搜模块名就会看到自定义的模块:
在这里插入图片描述
7、点击安装即可安装应用,不过当前应用中没有任何功能;
在这里插入图片描述
安装了为什么没有显示????请继续向下看
8、创建新的应用:
一个应用应包含如下部分元素:

	图标:用于在应用列表中的展示;
	顶级菜单项:其下位置所有的应用菜单项;
	应用安全组:通过权限访问仅对指定用户开发;

①、添加应用顶级菜单项:
A、在views目录下创建“library_menu.xml”文件来定义菜单项:

<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <menuitem id="menu_library" name="Library"/>
</odoo>

在这里插入图片描述
代码注释:

以上代码是odoo的数据文件,用于odoo数据库的记录,其中的元素是向“ir.ui.menu”模型写入记录,id作为唯一标识符;

B、在 manifest.py的data属性来添加创建的“library_menu.xml”文件;

'data': [
    'views/library_menu.xml',
],

在这里插入图片描述
注意:此时升级模块还不会有太大的效果,因为顶级菜单项中未包含可操作性的子菜单。
②、添加权限组:
A、权限的目的:

权限组主要用于用户在使用应用的相应权限,权限主要分为:普通用户权限组,额外配置的权限管理组;

B、接下来添加两个安全组,在security目录下创建library_security.xml文件中定义:

<?xml version="1.0" encoding="utf-8" ?>
<odoo>
 <!-- 在ir.module.category创建图书应用的分类-->
    <record id="module_library_category" model="ir.module.category">
        <field name="name">Library</field>
    </record>

 <!--添加安全组 如下添加了用户组-->
    <record id="library_group_user" model="res.groups">
        <field name="name">User</field>
        <field name="category_id" ref="module_library_category"/>
        <field name="implied_ids" eval="[(4,ref('base.group_user'))]"/>
    </record>

 <!-- 创建管理组-->
    <record id="library_group_manager" model="res.groups">
        <field name="name">Manager</field>
        <field name="category_id" ref="module_library_category"/>![在这里插入图片描述](https://img-blog.csdnimg.cn/20190530175404749.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjU3OTMyOA==,size_16,color_FFFFFF,t_70)
        <field name="implied_ids" eval="[(4,ref('library_group_user'))]"/>
        <field name="users" eval="[
                    (4,ref('base.user_root')),
                    (4,ref('base.user_admin'))
        ]"/>
    </record>
</odoo>

以上代码中字段说明:

以上代码将在res.groups模型中创建:
	name: 组名;
	category_id:关联应用,使用ref属性来通过XML ID链接已创建的分类;例如:链接创建图书对应的分类;
	implied_id:这是一个one-2-many关联字段,主要是一系列组来对组内用户生效,后面会详细介绍;
				例如用户组:我们使用内部用户组base.greoup_user;
				例如管理组:关联了图书用户组,以继承其权限;
	users:让管理组合内部超级管理员自动称为应用管理员;

C、在 manifest.py的data属性来添加创建的“library_security.xml”文件;

    'data': [
        # 'security/ir.model.access.csv',
        'security/library_security.xml',
        'views/library_menu.xml',
    ],

在这里插入图片描述
D、启动服务,在参数设置–>用户&公司–>群组 中可以查看:

在这里插入图片描述
9、模型层:
①、在models文件下创建模型文件“library_book.py”:

# -*- coding: utf-8 -*-

from odoo import models, fields, api

class Book(models.Model):
    _name = 'library.book'
    _description = 'Book'

    name = fields.Char('书名',required=True)
    isbn = fields.Char('ISDN')
    active = fields.Boolean('Active?',default=True)
    date_published = fields.Date()      # 出版时间
    image = fields.Binary('Cover')      #  存储图书封面的二进制字段
    publisher_id = fields.Many2one('res.partner',string='Publisher')        #  出版公司多对一关联
    author_ids = fields.Many2many('res.partner',string="Authors")           #  作者多对多关联

在这里插入图片描述
代码释义:

	_name:定义了Odoo全局对该模型引用的标识符;   必填项
	_description:模型说明;非必填项

②、在models目录下的“init.py”文件下导入library_book文件:

from . import library_book

③、当定义完以上字段,(需开启开发者模式)可在“参数设置–>技术–>模型中检查相关字段”:

在列表中搜索library.book,然后点击查看该模型,即可看到下图:
在这里插入图片描述
字段释义:

#  除上图中红色标记的自定义字段外,启动服务的时候,Odoo会自己创建出如下字段:
	id :是模型中每条记录的唯一数字标识符
	create_date和create_uid:分别为记录创建时间和创建者
	display_name:为所使用的记录提供文本显示,如其它记录引用它,它就会被计算并默认使用 name 字段中的文本
	write_date和write_uid:分别表示最后修改时间和修改者
	__last_update:是一个助手字段 ,它不存储在数据库,用于做并发检测

10、设置访问权限:
当启动服务的时候,也许你在日志里面已经看到如下WARNING,根据警告已经很明显的告诉我们该引用没有设置权限:

The model library.book has no access rules, consider adding one. E.g. access_library_book,access_library_book,model_library_book,base.group_user,1,0,0,0 

在这里插入图片描述
①、可在“参数设置–>技术–>访问权限”里面对相关权限进行查看:
在这里插入图片描述
A、权限通过‘security/ir.model.access.csv’文件来添加,添加该文件并加入如下内容:

id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_book_user,BookUser,model_library_book,library_group_user,1,0,0,0
access_book_manager,BookManager,model_library_book,library_group_manager,1,1,1,1

在这里插入图片描述
注意事项:

	文件第一行后不要留空格,否则会导致报错;

代码释义:

	id :是记录的外部标识符,在模块中唯一;
	name :描述性标题,在保证唯一时提供有用信息;
	model_id :是赋权模型的外部标识符,对于该模型,标识符为“model_library_book”;
	group_id :指名授权的安全组,在前面的“library_security.xml”文件中创建了library_group_user和library_group_manager;
	
# 以下字段 1代表拥有该权限,0则相反
	perm_read :读,在此处我们授予普通用户读权限,管理员所有权限;
	perm_write :写;
	perm_create :创建;
	perm_unlike :删除权限;

B、为了让权限生效,还需要在_manifest_.py的data属性中添加对新文件的引入:

    'data': [
        'security/library_security.xml',
        'security/ir.model.access.csv',
        'views/library_menu.xml',
    ],

此处需要注意:由于csv文件里面引用了“library_security.xml”文件的相关部分,因此需要放在其下面;
在这里插入图片描述
②、行级权限:
假设需求:
默认active标记为False的记录不可见,但用户在需要时可以使用过滤器来访问,假设不希望普通用户访问无效图书,因此需要通过记录规则来实现。
A、在security/library_security.xml文件中添加如下代码:

    <data noupdate="1">
        <record id="book_user_rule" model="ir.rule">
            <field name="name">Library Book User Access</field>
            <field name="model_id" ref="model_library_book"/>
            <field name="domain_force">
                [('active','=',True)]
            </field>
            <field name="groups" eval="[(4,ref('library_group_user'))]"/>
        </record>
    </data>

在这里插入图片描述
代码释义:
noupdate=“1” :表示这些记录在模型安装时会被创建,但在模型更新时不会重写,
目的是允许规则在后面自定义时在升级模型时自定义内容丢失。但是建议在开发过程置为0;
11、视图层(view):
①、添加菜单项:

<act_window id="action_library_book"
            name="Library Books"
            res_model="library.book"
            view_mode="tree,form"/>

<menuitem id="menu_library_book"
          name="Books"
          parent="menu_library"
          action="action_library_book"/>

在这里插入图片描述
代码释义:

	<act_window>元素定义客户端窗口操作,它按顺序通过启用列表和表单视图打开library.book 模型
	<menuitem>定义一个调用前面定义的action_library_book操作的顶级菜单项

启动服务,升级模块:
在这里插入图片描述
此时在界面可以看到菜单界面有了我们所安装的Library应用;
②、创建视图表单;
所有的视图都存在数据库ir.ui.view模型中。
A、添加view/book_view.xml文件来定义表单视图:

<?xml version="1.0" encoding="utf-8" ?>
<odoo>
    <record id="view_form_book" model="ir.ui.view">
        <field name="name">Book Form</field>
        <field name="model">library.book</field>
        <field name="arch" type="xml">
            <form string="Book">
                <group>
                    <field name="name"/>
                    <field name="author_ids" widget="many2many_tags"/>
                    <field name="publisher_id"/>
                    <field name="date_published"/>
                    <field name="isbn"/>
                    <field name="active"/>
                    <field name="image" widget="image"/>
                </group>
            </form>
        </field>
    </record>
</odoo>

在这里插入图片描述
代码释义:

	ir.ui.view中记录三个字段值:
		name:主要用于提供信息;
		model:模型名称;
		arch:包含视图的定义;
		<form>:包含了要在表单中显示的字段;

B、在data中进行声明:
在这里插入图片描述
刷新页面:
在这里插入图片描述
③、业务文件表单视图:
在odoo表单中包含两个元素:

	<header>:定义操作按钮;
	<sheet>:定义数据字段

如下代码:

        <form string="Book">
            <header>
                <!-- 此处添加按钮 -->
            </header>
            <sheet>
                <group>
                    <field name="name" />
                    ...
                </group>
            </sheet>
        </form>

④、添加操作按钮:
定义一个操作按钮,用于检测ISDN的有效性,逻辑代码放在Book模型中,方法命名为button_check_isdn(),暂时未创建,但是我们先可以在表单中添加相应按钮:

   <header>
        <button name="button_check_isdn" type="object"
                string="Check ISBN"/>
   </header>

在这里插入图片描述
代码释义:

按钮的基本属性有
	string: 定义按钮显示文本;
	type:执行的操作类型;
	name:操作的标识符;
	class:应用CSS样式的可选属性,与HTML相同;

⑤、使用组来组织表单:

	<group>标签可用于组织表单内容,在<group>元素内加<group>会在外层组中创建一个两列布局,
	推荐在group元素中添加name属性,易于其他模块对其进行继承。

A、修改代码如下:

            <sheet>
                <group name="group_top">
                    <group name="group_left">
                        <field name="name"/>
                        <field name="author_ids" widget="many2many_tags"/>
                        <field name="publisher_id"/>
                        <field name="date_published"/>
                    </group>
                    <group name="group_right">
                        <field name="isbn"/>
                        <field name="active"/>
                        <field name="image" widget="image"/>
                    </group>
                </group>
            </sheet>

在这里插入图片描述
B、启动刷新界面:
在这里插入图片描述
⑥、增加列表视图和搜索视图:
A、在book_view.xml文件中添加 tree 视图:

<record id="view_tree_book" model="ir.ui.view">
    <field name="name">Book List</field>
    <field name="model">library.book</field>
    <field name="arch" type="xml">
        <tree>
            <field name="name"/>
            <field name="author_ids" widget="many2many_tags"/>
            <field name="publisher_id"/>
            <field name="date_published"/>
        </tree>
    </field>
</record>

在这里插入图片描述
刷新界面,显示如下图:
在这里插入图片描述
B、定义搜索视图,观察上图会发现右上角有一个搜索框,搜索的字段和可用过滤器由视图定义,在book_view.xml文件中添加:

<!--搜索试图-->
<record id="view_search_book" model="ir.ui.view">
    <field name="name">Book FIlters</field>
    <field name="model">library.book</field>
    <field name="arch" type="xml">
        <search>
            <field name="publisher_id"/>
            <filter name="filter_active"
                    string="Active"
                    domain="[('active','=',True)]"/>
            <filter name="filter_inactive"
                    string="Inactive"
                    domain="[('active','=',False)]"/>
        </search>
    </field>
</record>

在这里插入图片描述
代码释义:

<field>元素定义在搜索框中输入搜索的字段,这里添加了publisher_id 自动提示出版商字段。
<filter>元素添加预定义过滤条件,用户进行点击来切换。odoo12中要求<filter>要包含name=""属性,唯一标识每个过滤器,如果不写验证会失败。

刷新界面,显示效果如下:
在这里插入图片描述
12、业务逻辑(model)
业务逻辑层主要编写应用的业务规则,如验证和自动计算,下来我们添加isbn验证按钮的业务逻辑;
①、添加业务逻辑
上面我们添加了一个ISBN有效验证的按钮,现在我们来实现,ISBN包含13位数字,最后一位由前面12位计算所得。

    @api.multi
    def _check_isbn(self):
        self.ensure_one()
        isbn = self.isbn.replace('-','')  
        digits = [int(x) for x in isbn if x.isdigit()]
        if len(digits) == 13:
            ponderations = [1,3]*6
            terms = [a * b for a,b in zip(digits[:12],ponderations)]
            remain = sum(terms) % 10
            check = 10 - remain if remain != 0 else 0
            return digits[-1] == check

在这里插入图片描述
然后继续添加按钮的代码:

@api.multi
def button_check_isbn(self):
    for book in self:
        if not book.isbn:
            raise Warning('Please privide an ISBN for %s'%book.name)
        if book.isbn and not book._check_isbn():
            raise Warning('%s is an invalid ISBN'% book.isbn)
        return True

在这里插入图片描述
此处需要注意导入Warning包:

from odoo.exceptions import Warning

代码释义:

	使用了@api.multi装饰器,此处的self便是一个记录集,然后遍历每一条记录,遍历所有已选图书,如果ISBN有值,
则检查有效性,若无值,则向用户抛出警告。

13、网页和控制器(controllers)
Odoo提供了一个web开发框架,用于开发与后台应用深度继承的功能;
接下来我们创建一个显示有效图书列表的简单网页;
A、在controllers目录下创建main.py文件

from odoo import http

class Books(http.Controller):
    
    @http.route('/library/books',auth='user')
    def list(self,**kwargs):
        Book = http.request.env['library.book']
        books = Book.search([])
        return http.request.render(
            'library_app.book_list_template',{'books':books}
        )

在这里插入图片描述
注意:在同main.py文件下的“init.py”文件中导入main文件
代码释义:

	这里使用了odoo.http,是提供网页相关功能的核心组件;
	http.Controller是需要继承的类控制器;
	@http.route装饰器,它声明了与类方法关联的URL地址,默认访问URL地址要求客户登录,推荐明确指出访问的授权模式,这里添加了auth='user'参数,
					如果允许公开访问,还可以添加auth='public'参数,但是在图书搜索前应使用sudo()进行提权;
	http.request.env获取环境,试用其从目录中获取有效图书记录集;
	http.request.render()通过字典来向模板传值;

B、QWeb模板是一个视图类型,应放在/views目录下,创建book_list_tenplate.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <template id="book_list_template" name="Book List">
        <div id="wrap" class="container">
            <h1>Books</h1>
            <t t-foreach="books" t-as="book">
                <div class="row">
                    <span t-field="book.name" />,
                    <span t-field="book.date_published" />,
                    <span t-field="book.publisher_id" />
                </div>
            </t>
        </div>
    </template>
</odoo>

在这里插入图片描述
注意:需要在data里面进行声明;
代码释义:

	<template>元素用于声明QWeb模板,实质就是存储模块的base模型;
	t-foreach用于遍历变量books的每一项,通过控制器http.request.render()调用来获取;
	t-field用于渲染记录字段的内容;

14、实现效果
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值