Odoo实现了一些有用的类和混合,使您可以轻松地在对象上添加常用的行为。本指南将详细介绍其中的大部分内容,包括示例和用例。
消息特征
消息集成
基本消息系统
将消息功能集成到模型中非常容易。简单地继承mail.thread
模型并将消息字段(及其适当的小部件)添加到表单视图中,可以立即启动和运行。
例子
让我们创建一个代表商务旅行的简单模型。由于组织这样的旅行通常涉及很多人和很多讨论,让我们在模型上添加对消息交换的支持。
class BusinessTrip(models.Model):
_name = 'business.trip'
_inherit = ['mail.thread']
_description = 'Business Trip'
name = fields.Char()
partner_id = fields.Many2one('res.partner', 'Responsible')
guest_ids = fields.Many2many('res.partner', 'Participants')
表单视图中:
<record id="businness_trip_form" model="ir.ui.view">
<field name="name">business.trip.form</field>
<field name="model">business.trip</field>
<field name="arch" type="xml">
<form string="Business Trip">
<!-- Your usual form view goes here
...
Then comes chatter integration -->
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
一旦您在模型中添加了颤振支持,用户就可以轻松地在模型的任何记录上添加消息或内部注释;它们中每一个都将发送一个通知(对于所有的消息追随者,对内部记录的员工(base.group_user)用户)。如果您的邮件网关和接收地址被正确配置,这些通知将通过电子邮件发送,并且可以直接从您的邮件客户端回复;自动路由系统将答案传到正确的线程上。
服务器端,一些助手功能可以帮助您轻松发送消息并管理记录中的追随者:
发布消息
message_post(self, body='', subject=None, message_type='notification', subtype=None, parent_id=False, attachments=None,content_subtype='html', **kwargs)
在现有线程中发布新消息,返回新mail.message ID
参数
- body (
str
) -- 消息的主体,通常是被清洁过的原始的HTML - message_type (
str
) -- 详见mail_message.type字段 - content_subtype (
str
) -- 如果是明码文本:将正文转换成HTML - parent_id (
int
) -- 在私下讨论的情况下,通过将父伙伴添加到消息中来处理对先前消息的答复 - attachments (
list(tuple(str,str))
) -- 在表单(name,content)中的附件元组列表,其中内容不是base64编码的 - **kwargs -- 额外的关键字参数将作为新mail.message 记录的默认列值使用
返回
新创建的mail.message ID
返回类型
message_post_with_view(views_or_xmlid, **kwargs):
助手方法使用view_id发送邮件/发布消息以使用ir.qweb引擎进行渲染。这种方法是独立的,因为模板中什么也没有并且设计者允许批量处理视图。 当模版处理ir ui 视图时这个方法可能会消失
参数
or ir.ui.view record (str
) -- 应该发送的视图的外部ID或记录
message_post_with_template(template_id, **kwargs)
用模板发送邮件的助手方法
参数
- template_id -- 要创建消息正文的模板的ID
- **kwargs -- 创建一个mail.compose.message向导(其继承自mail.message)参数
接收消息
当邮件网关处理新电子邮件时,调用这些方法。这些电子邮件可以是新线程(如果它们通过别名得到)或者简单地从现有线程回复。重写它们允许您根据电子邮件本身的某些值设置线程的记录值(即更新日期或电子邮件地址,添加CC的地址作为追随者等).
message_new(msg_dict, custom_values=None)
当给定的线程模型接收到新消息时,如果消息不属于现有线程,则由message_process调用
默认行为是创建相应模型(基于从消息中提取的一些非常基本的信息)的新记录。可以通过重写此方法来实现附加行为
参数
- msg_dict (
dict
) -- 包含电子邮件详细信息和附件的地图。详见message_process
和mail.message.parse
了解更多 - custom_values (
dict
) -- 在创建新线程记录时,可将附加字段值的可选字典传递给create();注意,这些值可能会覆盖来自消息的任何其他值
返回类型
返回
新创建的线程对象的id
message_update(msg_dict, update_vals=None)
当为现有线程接收新消息时,由message_process调用。默认行为是用从传入电子邮件中获取的update_vals更新记录
可以通过重写此方法来实现附加行为
参数
- msg_dict (
dict
) -- 包含电子邮件详细信息和附件的地图。详见message_process
和mail.message.parse()
了解更多 - update_vals (
dict
) -- 字典包含用于更新给定ID的记录的值;如果字典是None或void,则不执行写入操作
返回
True
追随者管理
message_subscribe(partner_ids=None, channel_ids=None, subtype_ids=None, force=True)
向记录追随者添加伙伴
参数
- partner_ids (
list(int)
) -- 订阅记录的合作伙伴的ID - channel_ids (
list(int)
) -- 将订阅记录的信道的ID - subtype_ids (
list(int)
) -- 通道/伙伴将订阅的子类型的ID(默认值是默认的子类型,如果为None
) - force -- 如果为真,则在使用参数中的子类型创建新的追随者之前删除现有的追随者
返回
成功/失败
返回类型
message_subscribe_users(user_ids=None, subtype_ids=None)
在message_subscribe上的包装器,使用用户而不是合作伙伴
参数
- user_ids (
list(int)
) -- 将订阅该记录的用户的ID; 如果为None
,订阅当前用户 - subtype_ids (
list(int)
) -- 频道/伙伴将订阅的子类型的ID
返回
成功
返回类型
message_unsubscribe(partner_ids=None, channel_ids=None)
从记录的追随者中删除合作伙伴
参数
- partner_ids (
list(int)
) -- 订阅记录的合作伙伴的I - channel_ids (
list(int)
) -- 将订阅记录的频道的ID
返回
True
返回类型
message_unsubscribe_users(user_ids=None)
在message_subscribe上的包装器,使用用户
参数
user_ids (list(int)
) -- 将被退还给记录的用户的ID;如果为None,取而代之的是当前用户
返回
True
返回类型
记录变化
mail
模块在字段上添加一个强大的跟踪系统,允许您在记录的聊天中记录到特定字段的更改。
若要向字段添加跟踪,则简单地添加track_visibility属性,其使用值 onchange
(如果仅在字段更改时才显示在通知中)或always
(如果该值应始终显示在更改通知中,即使该特定字段未更改-例如通过始终添加名称字段使通知更具解释性,这是有用的)
例子
让我们跟踪一下我们商务旅行的名称和责任的变化:
class BusinessTrip(models.Model):
_name = 'business.trip'
_inherit = ['mail.thread']
_description = 'Business Trip'
name = fields.Char(track_visibility='always')
partner_id = fields.Many2one('res.partner', 'Responsible',
track_visibility='onchange')
guest_ids = fields.Many2many('res.partner', 'Participants')
从现在开始,每次旅行的名字或负责人都会在记录上记下记录。name
字段将显示在通知中,并给出通知的更多上下文(即使名字没有改变)
子类型
子类型使您对消息有更大的粒度控制。子类型充当通知的分类系统,允许订阅文档的用户定制他们希望接收的通知的子类型.
子类型是作为模块中的数据创建的;该模型具有以下字段:
name
(强制的) - Char
子类型的名称,将显示在通知自定义弹出窗口中
description
- Char
将在为该子类型发布的消息中添加描述。如果无效,则将添加名称
internal
- Boolean
具有内部子类型的消息只能由雇员看到,也可以是base.group_user组的成员
parent_id
- Many2one
用于自动订阅的链接子类型;例如,项目子类型通过这个链接链接到任务子类型。当某人订阅某个项目时,他将订阅该项目的所有任务,并使用父子类型找到子类型
relation_field
- Char
例如,当连接项目和任务子类型时,关系字段是任务的project_id字段
res_model
- Char
该子类型应用于模型;如果为false,此子类型适用于所有模型
default
- Boolean
当订阅时,默认情况下子类型被激活
sequence
- Integer
用于排序通知自定义弹出窗口中的子类型
hidden
- Boolean
将子类型隐藏在通知自定义弹出窗口
与字段跟踪连接的子类型允许订阅不同类型的通知,这取决于用户可能感兴趣的内容。要做到这一点,可以重写 _track_subtype()
函数:
_track_subtype(init_values)
根据已更新的值给出记录上的更改触发的子类型
参数
init_values (dict
) -- 记录的原始值;在字典中只存在修改的字段
返回
子类型的完全外部id或False,如果没有子类型被触发
例子
让我们在我们的示例类中添加一个state字段,并在这个字段改变值时触发一个带有特定子类型的通知。
首先,让我们定义我们的子类型:
<record id="mt_state_change" model="mail.message.subtype">
<field name="name">Trip confirmed</field>
<field name="res_model">business.trip</field>
<field name="default" eval="True"/>
<field name="description">Business Trip confirmed!</field>
</record>
然后,我们需要重写track_subtype()
函数。跟踪系统调用该函数以根据当前应用的变化知道应该使用哪个子类型。在我们的例子中,当state字段从draft 更改为confirmed时,我们希望使用闪亮的新子类型:
class BusinessTrip(models.Model):
_name = 'business.trip'
_inherit = ['mail.thread']
_description = 'Business Trip'
name = fields.Char(track_visibility='onchange')
partner_id = fields.Many2one('res.partner', 'Responsible',
track_visibility='onchange')
guest_ids = fields.Many2many('res.partner', 'Participants')
state = fields.Selection([('draft', 'New'), ('confirmed', 'Confirmed')],
track_visibility='onchange')
def _track_subtype(self, init_values):
# init_values contains the modified fields' values before the changes
#
# the applied values can be accessed on the record as they are already
# in cache
self.ensure_one()
if 'state' in init_values and self.state == 'confirmed':
return 'my_module.mt_state_change' # Full external id
return super(BusinessTrip, self)._track_subtype(init_values)
自定义通知
当向追随者发送通知时,在模板中添加按钮以允许直接从电子邮件中快速操作可能是非常有用的。即使是一个简单的按钮,直接链接到记录的表单视图可能是有用的;但是,在大多数情况下,您不想将这些按钮显示给门户用户。
通知系统允许以以下方式自定义通知模板:
- 显示访问按钮:这些按钮在通知电子邮件的顶部可见,并允许收件人直接访问记录的表单视图
- 显示跟随按钮:这些按钮允许接收者直接从记录中快速订阅
- 显示不跟随按钮:这些按钮允许接收者直接从记录中退订
- 显示自定义操作按钮:这些按钮是对特定路由的调用,并允许您从电子邮件中直接获得一些有用的操作(即转换为一个机会,验证费用管理器的费用表等)
这些按钮设置可以应用于不同的组,您可以通过重写函数 _notification_recipients
来定义自己需要的
_notification_recipients(message, groups)
根据已更新的值给出记录上的更改触发的子类型
参数
- message (
record
) -- 当前正在发送的mail.message
记录 - groups (
list(tuple)
) --表格的元组列表(group_name, group_func,group_data) :
group_name
是仅用于能够覆盖和操作组的标识符。默认组是
user
(与雇员用户链接的收件人),portal
(链接到门户用户的收件人) 和customer
(未链接到任何用户的收件人)。覆盖使用的一个例子是添加一个链接到res.groups的组,例如人力资源干事对他妈设置特定的操作按钮group_func
是一个函数指针,它将伙伴记录作为参数。该方法将应用于接收者,以了解它们是否属于给定的组。只保留第一匹配组。评估顺序是列表顺序
group_data
是一个字典,其包含了使用以下可能的keys - values的通知电子邮件的参数:
-
has_button_access
是否在电子邮件中显示Access <Document>。默认情况下,对于新组来说是True,对于门户网站/客户来说是False
-
button_access
带有URL和按钮标题的字典
-
has_button_follow
是否显示后续电子邮件(如果收件人当前没有跟踪线程)。默认情况下,对于新组来说是True,对于门户网站/客户来说是False
-
button_follow
带有URL和按钮标题的字典
-
has_button_unfollow
是否在电子邮件中显示未跟踪(如果收件人当前正在跟踪线程)。默认情况下,对于新组来说是True,对于门户网站/客户来说是False
-
button_unfollow
带有URL和按钮标题的字典
-
actions
在通知电子邮件中显示的操作按钮列表。每个操作是一个包含URL和按钮标题的字典
-
Returns
子类型的完全外部id或False,如果没有子类型被触发
动作列表中的URL可以通过调用 _notification_link_helper()
函数自动生成:
_notification_link_helper(self, link_type, **kwargs)
在当前记录(或在特定的记录上,如果设置了kwargs model
和res_id
)上生成给定类型的链接
参数
link_type (str
) --
要生成的链接类型;可以是这些值中的任何一个:
view
链接到记录的表单视图
assign
a将记录的用户分配给记录的user_id字段(如果存在)
follow
自解释
unfollow
自解释
workflow
触发工作流信号;信号的名称应作为kwarg signal提供
method
在记录上调用方法;方法的名称应该作为kwarg method
提供
new
打开一个新记录的空表单视图;您可以通过在kwarg action_id
中提供其id(数据库id或完全解析的外部id)来指定特定的操作
返回
为记录选择的类型的链接
返回类型
例子
让我们添加自定义按钮到出商务旅行态更改通知;这个按钮将重置状态到Draft,并且将只对(虚构)组旅行管理者(business.group_trip_manager
)的成员可见
class BusinessTrip(models.Model):
_name = 'business.trip'
_inherit = ['mail.thread', 'mail.alias.mixin']
_description = 'Business Trip'
# Pevious code goes here
def action_cancel(self):
self.write({'state': 'draft'})
def _notification_recipients(self, message, groups):
""" Handle Trip Manager recipients that can cancel the trip at the last
minute and kill all the fun. """
groups = super(BusinessTrip, self)._notification_recipients(message, groups)
self.ensure_one()
if self.state == 'confirmed':
app_action = self._notification_link_helper('method',
method='action_cancel')
trip_actions = [{'url': app_action, 'title': _('Cancel')}]
new_group = (
'group_trip_manager',
lambda partner: bool(partner.user_ids) and
any(user.has_group('business.group_trip_manager')
for user in partner.user_ids),
{
'actions': trip_actions,
})
return [new_group] + groups
请注意,我可以在这个方法之外定义我的评估函数,并且定义一个全局函数来代替lambda完成它,但是为了在这些文档文件中更简短和更少冗长,有时我很无聊,我选择前者而不是后者。
重写默认值
有几种方法可以自定义mail.thread模型的行为,包括(但不限于):
_mail_post_access
- Model
属性
所需的访问权限能够在模型上发布消息;默认情况下,需要进行write
访问,也可以设置为read访问
上下文键:
这些上下文键可在调用 create()
或 write()
(或其他可能有用的方法)用于时稍微控制mail.thread特性,如自动订阅或字段跟踪
mail_create_nosubscribe
: 在创建或message_pos中,不要将当前用户订阅到记录线程mail_create_nolog
: 在创建时,不要记录自动'<Document> created'消息mail_notrack
: 在创建和写入时,不执行创建消息的值跟tracking_disable
: 在创建和写入时,不执行MailThread特性(自动订阅、跟踪、发布 ...)mail_auto_delete
: 自动删除邮件通知;默认情况下为Truemail_notify_force_send
: 如果发送的电子邮件通知少于50个,则直接发送它们,而不是使用队列;默认情况下为Truemail_notify_user_signature
: 在电子邮件通知中添加当前用户签名;默认情况下为True
邮件别名
A别名是可配置的电子邮件地址,链接到特定的记录(通常继承自 mail.alias.mixin
模型) ,当通过电子邮件联系时,将创建新记录。它们是一种简单的方法,使您的系统能够从外部访问,允许用户或客户快速创建数据库中的记录,而不需要直接连接到Odoo
别名vs传入邮件网关
有些人为了同样的目的使用邮件网关。您仍然需要一个正确配置的邮件网关来使用别名,然而,单个路由域将是足够的,因为所有路由将在Odoo内完。别名比邮件网关有几个优点:
-
更易于配置
- 多个别名可以使用单个传入网关;这避免了在您的域名(所有配置都在Odoo内部完成)上配置多个电子邮件
- 无需配置访问别名的系统访问权限
-
更连贯
- 可配置在相关记录上,而不在设置子菜单
-
更容易重写服务器端
- 混合模型是从一开始就扩展的,允许您比邮件网关更容易地从传入电子邮件中提取有用的数据
别名支持集成
别名通常配置在父模型上,然后当通过电子邮件联系时创建特定记录。例如,项目有别名来创建任务或问题,销售团队有别名生成领导。
注
由别名创建的模型必须继承mail_thread模型
别名支持通过继承而mail.alias.mixin添加;此混合将为生成的父类的每个记录生成一个新的mail.alias记录(例如,每一个project.project记录都会在创建时初始化其mail.alias记录)
注
别名也可以手动创建,并由简单的Many2one
字段支持。本指南假定您希望自动创建别名、记录特定默认值等更完整的集。
不像mail.thread
继承,mail.alias.mixin
必需要一些特定的重写才能正确工作。一些特定的重写可以正确工作 。这些重写将指定所创建的别名的值,如它必须创建的记录类型,以及这些记录可能依赖于父对象所具有的某些默认值:
get_alias_model_name(vals)
返回别名的模型名。 不回复现有记录的传入电子邮件将导致创建该别名模型的新记。该值可能取决于vals,当创建该模型的记录时,字典值传递给create
参数
dict (vals
) -- 将创建别名的新创建的记录的值
返回
模型名称
返回类型
get_alias_values()
返回值以创建别名,或在创建别名后写入别名。虽然不是完全强制的,但通常需要通过在别名的alias_default字段中设置默认值字典来确保新创建的记录将链接到别名的父级(即在正确项目中创建的任务)
返回
将写入新别名的值的字典
返回类型
get_alias_values()
重写是特别有趣的,因为它允许您容易地修改别名的行。在可以设置别名的字段中,以下是特别感兴趣的:
alias_name
- Char
电子邮件别名的名称, 例如 'jobs' ,如果你想为<jobs@example.odoo.com>捕获电子邮件
alias_user_id
- Many2one
(res.users
)
在该别名上接收电子邮件时创建的记录的所有者;如果没有设置该字段,系统将尝试基于发送者(From)地址找到正确的所有者,或者如果没有找到该地址的系统用户,则将使用管理员帐户
alias_defaults
- Text
Python字典,将在为该别名创建新记录时被评估为提供默认值
alias_force_thread_id
- Integer
一个线程(记录)的可选ID,所有的传入消息将被附加,即使它们没有回复它;如果设置,则将完全禁用新记录的创建
alias_contact
- Selection
使用邮件网关在文档上发布消息的策略
- everyone: 每个人都可以发布
- partners: 仅经过认证的合作伙伴
- followers: 只有相关文件的追随者或以下频道的成员
请注意别名使用委托继承,这意味着别名存储在另一个表中时,您可以直接从父对象访问所有这些字段。这允许您从记录的表单视图中容易地配置别名
例子
让我们在商务旅行类中添加别名,通过电子邮件即时创建费用
class BusinessTrip(models.Model):
_name = 'business.trip'
_inherit = ['mail.thread', 'mail.alias.mixin']
_description = 'Business Trip'
name = fields.Char(track_visibility='onchange')
partner_id = fields.Many2one('res.partner', 'Responsible',
track_visibility='onchange')
guest_ids = fields.Many2many('res.partner', 'Participants')
state = fields.Selection([('draft', 'New'), ('confirmed', 'Confirmed')],
track_visibility='onchange')
expense_ids = fields.One2many('business.expense', 'trip_id', 'Expenses')
alias_id = fields.Many2one('mail.alias', string='Alias', ondelete="restrict",
required=True)
def get_alias_model_name(self, vals):
""" Specify the model that will get created when the alias receives a message """
return 'business.expense'
def get_alias_values(self):
""" Specify some default values that will be set in the alias at its creation """
values = super(BusinessTrip, self).get_alias_values()
# alias_defaults holds a dictionnary that will be written
# to all records created by this alias
#
# in this case, we want all expense records sent to a trip alias
# to be linked to the corresponding business trip
values['alias_defaults'] = {'trip_id': self.id}
# we only want followers of the trip to be able to post expenses
# by default
values['alias_contact'] = 'followers'
return values
class BusinessExpense(models.Model):
_name = 'business.expense'
_inherit = ['mail.thread']
_description = 'Business Expense'
name = fields.Char()
amount = fields.Float('Amount')
trip_id = fields.Many2one('business.trip', 'Business Trip')
partner_id = fields.Many2one('res.partner', 'Created by')
我们希望我们的别名可以从商务旅行的表单视图中容易地配置,所以让我们在下面的表单视图中添加以下内容:
<page string="Emails">
<group name="group_alias">
<label for="alias_name" string="Email Alias"/>
<div name="alias_def">
<!-- display a link while in view mode and a configurable field
while in edit mode -->
<field name="alias_id" class="oe_read_only oe_inline"
string="Email Alias" required="0"/>
<div class="oe_edit_only oe_inline" name="edit_alias"
style="display: inline;" >
<field name="alias_name" class="oe_inline"/>
@
<field name="alias_domain" class="oe_inline" readonly="1"/>
</div>
</div>
<field name="alias_contact" class="oe_inline"
string="Accept Emails From"/>
</group>
</page>
现在我们可以直接从表单视图中更改别名地址,并更改谁可以发送电子邮件到别名。
然后,我们可以在开销模型上重写message_new()以在创建费用时从电子邮件中获取值:
class BusinessExpense(models.Model):
# Previous code goes here
# ...
def message_new(self, msg, custom_values=None):
""" Override to set values according to the email.
In this simple example, we simply use the email title as the name
of the expense, try to find a partner with this email address and
do a regex match to find the amount of the expense."""
name = msg_dict.get('subject', 'New Expense')
# Match the last occurence of a float in the string
# Example: '50.3 bar 34.5' becomes '34.5'. This is potentially the price
# to encode on the expense. If not, take 1.0 instead
amount_pattern = '(\d+(\.\d*)?|\.\d+)'
expense_price = re.findall(amount_pattern, name)
price = expense_price and float(expense_price[-1][0]) or 1.0
# find the partner by looking for it's email
partner = self.env['res.partner'].search([('email', 'ilike', email_address)],
limit=1)
defaults = {
'name': name,
'amount': price,
'partner_id': partner.id
}
defaults.update(custom_values or {})
res = super(BusinessExpense, self).message_new(msg, custom_values=defaults)
return res
网站特色
访客跟踪
utm.mixin
类可以通过链接到指定资源的参数来跟踪在线营销/传播活动。混合给你的模型增加了3个字段:
campaign_id
:Many2one
字段到一个utm.campaign
对象(即Christmas_Special, Fall_Collection等)source_id
:Many2one
字段到一个utm.source
对象(即Search Engine, mailing list等)medium_id
:Many2one
字段到一个utm.medium
对象(即Snail Mail, e-Mail, social network update等)
这些模型只有一个字段 name
(也就是说,他们只是为了区分运动,但没有任何特定的行为)。
一旦客户访问您的网站,这些参数设置在url中 (即 http://www.odoo.com/?campaign_id=mixin_talk&source_id=www.odoo.com&medium_id=website),在访问者的网站中设置三个cookies用于这些参。一个继承utm.mixin的对象是从网站创建的(即lead form, job application等), utm.mixin 代码启动并从cookie中获取值以将它们设置在新记录中。Once this is done, you can then use the campaign/source/medium fields as any other field when defining reports and views 一旦完成这一操作,就可以在定义报表和视图时使用campaign/source/medium字段作为任何其他字段(按组,等等)。
为了扩展这种行为,简单的添加一个关系字段到一个简单的模型(模型应该支持快速创建(即使用单个name
值调用create()
)和扩展的函数tracking_fields()
中:
class UtmMyTrack(models.Model):
_name = 'my_module.my_track'
_description = 'My Tracking Object'
name = fields.Char(string='Name', required=True)
class MyModel(models.Models):
_name = 'my_module.my_model'
_inherit = ['utm.mixin']
_description = 'My Tracked Object'
my_field = fields.Many2one('my_module.my_track', 'My Field')
@api.model
def tracking_fields(self):
result = super(MyModel, self).tracking_fields()
result.append([
# ("URL_PARAMETER", "FIELD_NAME_MIXIN", "NAME_IN_COOKIES")
('my_field', 'my_field', 'odoo_utm_my_field')
])
return result
这将告诉系统创建一个名为odoo_utm_my_field 的cookie,其值可以在url参数my_field中找到;一旦这个模型的新记录是由网站表单调用创建的,utm.mixin的create()方法的泛型将从cookie中获取该字段的默认值(并且my_module.my_track
记录将及时创建,如果它不存在的话)
你可以在下面的模型中找到集成的具体例子:
crm.lead
在CRM (crm)应用程序中hr.applicant
在Recruitment Process (hr_recruitment)应用程序中helpdesk.ticket
在Helpdesk (helpdesk - Odoo Enterprise only) 应用程序中
网站可见性
您可以很容易地添加网站可见性切换在您的任何记。虽然这个混合很容易手动实现,但它是mail.thread继承之后最常用的工具;证明了它的实用性。这个混用的典型用例是任何具有前端页面的对象;能够控制页面的可见性允许您在编辑页面时花费时间,并且在您满意的时候才发布它。
要包含功能性,只需要继承website.published.mixin
:
class BlogPost(models.Model):
_name = "blog.post"
_description = "Blog Post"
_inherit = ['website.published.mixin']
这个混合在你的模型上增加了2个字段:
注意,最后一个字段是计算字段,必须为您的类实现:
def _compute_website_url(self):
for blog_post in self:
blog_post.website_url = "/blog/%s" % (log_post.blog_id)
一旦机制到位,您只需调整前端和后端视图即可访问。在后端,在按钮框中添加按钮通常是一种方法:
<button class="oe_stat_button" name="website_publish_button"
type="object" icon="fa-globe">
<field name="website_published" widget="website_button"/>
</button>
在前端,需要进行一些安全检查,以避免向网站访问者显示“编辑”按钮:
<div id="website_published_button" class="pull-right"
groups="base.group_website_publisher"> <!-- or any other meaningful group -->
<t t-call="website.publish_management">
<t t-set="object" t-value="blog_post"/>
<t t-set="publish_edit" t-value="True"/>
<t t-set="action" t-value="'blog.blog_post_action'"/>
</t>
</div>
注意,必须将对象作为变量object传递给模板;在这个例子中,blog.post记录作为blog_post变量传递给qweb渲染引擎,有必要将其指定给发布管理模板。publish_edit
变量允许前端按钮链接到后端 (允许您轻松地从前端切换到后端,反之亦然);如果设置了,则必须在action变量的后端指定要调用的动作的完整外部id(意该模型必须存在表单视图)。
操作 website_publish_button
在混合中定义并将其行为适应于对象:如果该类有一个有效的website_url计算函数,当用户单击该按钮时,用户将被重定向到前端;然后用户可以直接从前端发布页面。这确保了在线发布不可能偶然发生。如果没有计算函数,则简单地触发布尔website_published
网站元数据
这个简单的混合只允许您轻松地在前端页面中注入元数据
class BlogPost(models.Model):
_name = "blog.post"
_description = "Blog Post"
_inherit = ['website.seo.metadata', 'website.published.mixin']
这个混合在你的模型上增加了3个字段:
website_meta_title
: 允许您为页面设置附加标题的Char
字段website_meta_description
: 包含页面简短描述的Char
字段 (有时用于搜索引擎结果)website_meta_keywords
:Char
字段包含一些关键字,以帮助搜索引擎更精确地对页面进行分类;“推广”工具将帮助您轻松选择与词汇相关的关键词
这些字段使用编辑器工具栏中的“推广”工具在前端编辑。设置这些字段可以帮助搜索引擎更好地索引页面。请注意,搜索引擎不把他们的结果只在这些元数据;最好的搜索引擎优化实践仍然应该得到可靠的来源引。
其他
客户评级
评级混合允许发送电子邮件,要求客户评级,自动转换在看板过程中,并汇总统计你的评级
在模型中添加评级
要添加评级支持,只需继承rating.mixin模型:
class MyModel(models.Models):
_name = 'my_module.my_model'
_inherit = ['rating.mixin', 'mail.thread']
user_id = fields.Many2one('res.users', 'Responsible')
partner_id = fields.Many2one('res.partner', 'Customer')
混合的行为适合于你的模型:
-
rating.rating
记录将链接到你的模型(如果字段存在)的partner_id
字段- 如果使用另一个字段而不是partner_id,则可以用函数rating_get_partner_id()来重写此行为
-
rating.rating
记录将链接到模型的user_id段的合作伙伴(如果字段存在) (即被评级的合作伙伴)- 如果使用另一个字段而不是user_id,则该行为可以被函数rating_get_rated_partner_id()重写(注意,函数必须返回一个res.partner,对于user_id,系统自动获取用户的合作伙伴)
- 震动历史将显示评级事件 (如果你从mail.thread继承模型)
通过电子邮件发送评级请求
如果您希望发送电子邮件请求评级,只需生成带有评级对象链接的电子邮件。一个非常基本的电子邮件模板可以是这样的:
<record id="rating_my_model_email_template" model="mail.template">
<field name="name">My Model: Rating Request</field>
<field name="email_from">${object.rating_get_rated_partner_id().email or '' | safe}</field>
<field name="subject">Service Rating Request</field>
<field name="model_id" ref="my_module.model_my_model"/>
<field name="partner_to" >${object.rating_get_partner_id().id}</field>
<field name="auto_delete" eval="True"/>
<field name="body_html"><![CDATA[
% set access_token = object.rating_get_access_token()
<p>Hi,</p>
<p>How satsified are you?</p>
<ul>
<li><a href="/rating/${access_token}/10">Satisfied</a></li>
<li><a href="/rating/${access_token}/5">Not satisfied</a></li>
<li><a href="/rating/${access_token}/1">Very unsatisfied</a></li>
</ul>
]]></field>
</record>
然后,你的客户将收到一个电子邮件链接到一个简单的网页,允许他们提供反馈他们与你的用户的互动(包括免费的文本反馈信息)。
然后,通过定义评级的操作,您可以很容易地将您的评级与表单体视图集成:
<record id="rating_rating_action_my_model" model="ir.actions.act_window">
<field name="name">Customer Ratings</field>
<field name="res_model">rating.rating</field>
<field name="view_mode">kanban,pivot,graph</field>
<field name="domain">[('res_model', '=', 'my_module.my_model'), ('res_id', '=', active_id), ('consumed', '=', True)]</field>
</record>
<record id="my_module_my_model_view_form_inherit_rating" model="ir.ui.view">
<field name="name">my_module.my_model.view.form.inherit.rating</field>
<field name="model">my_module.my_model</field>
<field name="inherit_id" ref="my_module.my_model_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<button name="%(rating_rating_action_my_model)d" type="action"
class="oe_stat_button" icon="fa-smile-o">
<field name="rating_count" string="Rating" widget="statinfo"/>
</button>
</xpath>
</field>
</record>
请注意,对于评级有默认视图 (kanban,pivot,graph),可以让用户快速查看客户的评级
你可以在下面的模型中找到集成的具体例子:
project.task
在Project (rating_project) 应用程序中helpdesk.ticket
在Helpdesk (helpdesk - Odoo Enterprise only) 应用程序中
ps:有翻译不当之处,欢迎留言指正。
原文地址:https://www.odoo.com/documentation/10.0/reference/mixins.html