Mixins and Useful Classes: Mixins和有用的类
Odoo实现了一些有用的类和mixin,使您可以轻松地在对象上添加常用的行为。本指南将通过示例和用例详细介绍其中的大部分内容。
消息功能
消息集成
将消息传递功能集成到您的模型非常容易。只需继承’mail.thread’模型并将消息传递字段(及其相应的小部件)添加到表单视图中,即可立即启动并运行。
Example
创建一个代表商务旅行的简单模型。由于组织这种旅行通常涉及很多人和很多讨论,在模型上添加对消息交换的支持。
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, **kwargs)
在现有线程中发布新消息,返回新的mail.message ID。
message_post_with_view(views_or_xmlid, **kwargs):
帮助方法使用view_id发送邮件/发布消息以使用ir.qweb引擎进行呈现。此方法是独立的,因为模板和编写器中没有任何内容允许批量处理视图。当模板处理ir ui视图时,此方法可能会消失。
message_post_with_template(template_id, **kwargs)
帮助方法发送带有模板的邮件
接收消息
当邮件网关处理新电子邮件时,将调用这些方法。这些电子邮件可以是新线程(如果它们通过别名到达)或只是从现有线程回复。重写它们允许您根据电子邮件本身的某些值设置线程记录的值(即更新日期或电子邮件地址,添加CC的地址作为关注者等)。
message_new(msg_dict, custom_values=None)
当收到给定线程模型的新消息时,如果消息不属于现有线程,则由message_process调用。
默认行为是创建相应模型的新记录(基于从消息中提取的一些非常基本的信息)。可以通过重写此方法来实现其他行为。
message_update(msg_dict, update_vals=None)
当收到现有线程的新消息时,由message_process调用。默认行为是使用从传入电子邮件中获取的update_vals更新记录。可以通过重写此方法来实现其他行为。
关注者管理
message_subscribe(partner_ids=None, channel_ids=None, subtype_ids=None, force=True)
将合作伙伴添加到记录关注者.
message_unsubscribe(partner_ids=None, channel_ids=None)
从记录的关注者中删除合作伙伴。
message_unsubscribe_users(user_ids=None)
使用用户在message_subscribe上包装。
记录更改
邮件模块在字段上添加了强大的跟踪系统,允许您记录对记录聊天中特定字段的更改。
要向字段添加跟踪,只需使用值添加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')
从现在开始,对旅行名称或负责人的每次更改都会记录记录中的注释。名称字段也将显示在通知中,以提供有关通知的更多上下文(即使名称未更改)。
子类型
子类型使您可以更精细地控制消息。子类型充当通知的分类系统,允许文档的订阅者定制他们希望接收的通知的子类型。
Example
在示例类上添加一个状态字段,并在此字段更改值时触发具有特定子类型的通知。
# 首先,定义子类型:
<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()函数。跟踪系统调用此函数以根据当前应用的更改知道应使用哪个子类型。在我们的例子中,当状态字段从草稿更改为已确认时,我们希望使用我们新子类型:
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)
根据已更新的值,为记录上的更改触发子类型。
_notification_link_helper(self, link_type, **kwargs)
在当前记录上生成给定类型的链接(如果设置了kwargs模型和res_id,则在特定记录上生成)。
Example
# 让我们为Business Trip状态更改通知添加一个自定义按钮;此按钮会将状态重置为草稿,并且仅对(虚构)组旅行经理
# (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 attribute
能够在模型上发布消息所需的访问权限;默认情况下,需要写访问权限,也可以设置为读取
上下文键:
这些上下文密钥可用于在调用create()或write()(或任何其他可能有用的方法)期间控制mail.thread功能,如自动订阅或字段跟踪。
- mail_create_nosubscribe: 在create或message_post,不要将当前用户订阅到记录线程
- mail_create_nolog: 在创建时,不要自动记录“ created”消息
- mail_notrack: 在创建和写入时,不要执行值跟踪创建消息
- tracking_disable: 在创建和写入时,不执行MailThread功能(自动订阅,跟踪,发布,…)
- mail_auto_delete: 自动删除邮件通知;默认为True
- mail_notify_force_send: 如果发送的电子邮件通知少于50个,则直接发送而不是使用队列;默认为True
- mail_notify_user_signature: 在电子邮件通知中添加当前用户签名;默认为True
Mail alias(邮件别名)
别名是可配置的电子邮件地址,链接到特定记录(通常继承mail.alias.mixin模型),在通过电子邮件联系时将创建新记录。它们是一种简单的方法,可以从外部访问您的系统,允许用户或客户在数据库中快速创建记录,而无需直接连接到Odoo。
别名与传入邮件网关
有些人使用传入邮件网关实现同样的目的。您仍然需要一个正确配置的邮件网关来使用别名,但是单个catchall域就足够了,因为所有路由都将在Odoo中完成. 与邮件网关相比,别名有几个优点:
- 更容易配置
- 许多别名可以使用单个传入网关;这避免了必须在您的域名上配置多个电子邮件(所有配置都在Odoo内部完成)
- 无需系统访问权限即可配置别名
- 更连贯
- 可在相关记录上配置,而不在“设置”子菜单中配置
- 更容易覆盖服务器端
- Mixin模型可以从一开始就进行扩展,使您可以比使用邮件网关更轻松地从传入的电子邮件中提取有用的数据。
别名支持集成
别名通常在父模型上配置,然后在通过电子邮件联系时创建特定记录。例如,Project有别名来创建任务或问题,Sales Team有别名来生成Leads。
将由别名创建的模型必须继承mail_thread模型。
通过继承mail.alias.mixin添加别名支持;这个mixin将为创建的父类的每个记录生成一个新的mail.alias记录(例如,每个project.project记录都在创建时初始化了mail.alias记录)
别名也可以手动创建,并由简单的Many2one字段支持。本指南假设您希望与自动创建别名,特定于记录的默认值等进行更完整的集成。
与mail.thread继承不同,mail.alias.mixin需要一些特定的覆盖才能正常工作。这些覆盖将指定创建的别名的值,例如它必须创建的记录类型,以及这些记录可能具有的一些默认值,具体取决于父对象.
活动跟踪
活动是用户必须对文档进行的操作,如拨打电话或组织会议。邮件模块附带活动,因为它们集成在Chatter中,但未与mail.thread捆绑在一起。活动是mail.activity类的记录,具有类型(mail.activity.type),名称,描述,预定时间(等等)。待处理活动在聊天窗口小部件中的消息历史记录上方可见。
您可以使用对象上的mail.activity.mixin类和特定小部件集成活动,以在表单视图和视图的看板视图中显示它们(通过字段activity_ids)
Example
组织商务旅行是一个繁琐的过程,跟踪所需的活动,如订购机票或机场出租车可能是有用的。为此,我们将在模型中添加活动mixin,并在我们旅行的消息历史中显示下一个计划的活动。
class BusinessTrip(models.Model):
_name = 'business.trip'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = 'Business Trip'
name = fields.Char()
# [...]
修改行程的表单视图以显示其下一个活动:
<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 -->
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="activity_ids" widget="mail_activity"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
可以在以下模型中找到集成的具体示例:
- crm.lead in the CRM (crm) Application
- sale.order in the Sales (sale) Application
- project.task in the Project (poject) Application
Website features(网站功能)
访客跟踪
utm.mixin类可用于通过指向指定资源的链接中的参数来跟踪在线营销/通信活动。mixin为您的模型添加了3个字段:
- campaign_id: Many2one field to a utm.campaign object (i.e. Christmas_Special, Fall_Collection, etc.)
- source_id: Many2one field to a utm.source object (i.e. Search Engine, mailing list, etc.)
- medium_id: Many2one field to a utm.medium object (i.e. Snail Mail, e-Mail, social network update, etc.)
这些模型具有单个字段名称(即,它们仅用于区分活动但没有任何特定行为)。
一旦客户访问您的网站,并在网址中设置这些参数(即http://www.odoo.com/?campaign_id=mixin_talk&source_id=www.odoo.com&medium_id=website)
访问者的网站上为这些参数设置了三个cookie。一旦从网站创建了继承utm.mixin的对象(即主要表单,工作申请等),utm.mixin代码启动并从cookie中获取值以将其设置在新记录中。完成此操作后,您可以在定义报告和视图(分组依据等)时将campaign / source / medium字段用作任何其他字段。
要扩展此行为,只需将关系字段添加到简单模型(模型应支持快速创建(即使用单个名称值调用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 in the CRM (crm) Application
- hr.applicant in the Recruitment Process (hr_recruitment) Application
- helpdesk.ticket in the Helpdesk (helpdesk - Odoo Enterprise only) Application
网站可见性
您可以非常轻松地在任何记录上添加网站可见性切换。虽然这个mixin很容易手动实现,它是mail.thread继承之后最常用的;证明其有用性。这个mixin的典型用例是任何具有前端页面的对象;能够控制页面的可见性使您可以在编辑页面时花些时间,只有在满意时才发布它。
要包含functionnality,您只需要继承website.published.mixin:
class BlogPost(models.Model):
_name = "blog.post"
_description = "Blog Post"
_inherit = ['website.published.mixin']
此mixin在您的模型上添加了2个字段:
- website_published:布尔字段,表示发布的状态
- website_url:Char字段,表示访问对象的URL
请注意,最后一个字段是计算字段,必须为您的类实现:
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="float-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>
请注意,您必须将对象作为变量对象传递给模板;在此示例中,blog.post记录作为blog_post变量传递给qweb呈现引擎,有必要将其指定给发布管理模板。publish_edit变量允许前端按钮链接到后端(允许您从前端切换到后端,反之亦然);
动作website_publish_button在mixin中定义并使其行为适应您的对象:如果该类具有有效的website_url计算功能,则用户在单击按钮时会被重定向到前端;然后,用户可以直接从前端发布页面。这确保了不会偶然发生在线发布。如果没有compute函数,则只触发boolean website_published。
网站元数据
这个简单的mixin只允许您轻松地在前端页面中注入元数据。
class BlogPost(models.Model):
_name = "blog.post"
_description = "Blog Post"
_inherit = ['website.seo.metadata', 'website.published.mixin']
这个mixin在你的模型上增加了3个字段:
- website_meta_title: Char 允许您为页面设置其他标题的字段
- website_meta_description: Char 包含页面简短描述的字段(有时用于搜索引擎结果)
- website_meta_keywords: Char 包含一些关键字的字段,以帮助您的网页更精确地被搜索引擎分类; “推广”工具将帮助您轻松选择与词汇相关的关键词
可以使用“编辑器”工具栏中的“提升”工具在前端中编辑这些字段。设置这些字段可以帮助搜索引擎更好地索引您的网页。请注意,搜索引擎不会仅将结果基于这些元数据;最好的SEO实践应该仍然是可靠的来源引用。
Others
客户评级
评级mixin允许发送电子邮件以询问客户评级,在看板过程中自动转换以及汇总有关评级的统计信息。
在您的模型上添加评级
要添加评级支持,只需继承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')
mixin的行为适应您的模型
-
The rating.rating record will be linked to the partner_id field of your model (if the field is present).
- this behaviour can be overriden with the function rating_get_partner_id() if you use another field than partner_id
-
The rating.rating record will be linked to the partner of the user_id field of your model (if the field is present) (i.e. the partner who is rated)
- this behaviour can be overriden with the function rating_get_rated_partner_id() if you use another field than user_id (note that the function must return a res.partner, for user_id the system automatically fetches the partner of the user)
-
The chatter history will display the rating event (if your model inherits from 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>
请注意,评级有默认视图(看板,枢轴,图形),可让您快速鸟瞰客户评级。 您可以在以下模型中找到集成的具体示例:
- project.task in the Project (rating_project) Application
- helpdesk.ticket in the Helpdesk (helpdesk - Odoo Enterprise only) Application