## 模型约束
Odoo提供了两种方式设置自动验证的不变量: [`Python constraints`](https://www.odoo.com/documentation/9.0/reference/orm.html#openerp.api.constrains "openerp.api.constrains") 和 [`SQL constraints`](https://www.odoo.com/documentation/9.0/reference/orm.html#openerp.models.Model._sql_constraints "openerp.models.Model._sql_constraints").
Python的约束被定义为一种装饰 [`constrains()`](https://www.odoo.com/documentation/9.0/reference/orm.html#openerp.api.constrains "openerp.api.constrains"), 在一个记录集调用。装饰指定领域的参与约束,这样的约束是自动评估时,其中一个是修饰。如果它的不变是不满意的,该方法将提高一个例外:
~~~ python
from openerp.exceptions import ValidationError
@api.constrains('age')
def _check_something(self):
for record in self:
if record.age > 20:
raise ValidationError("Your record is too old: %s" % record.age)
# all records passed the test, don't return anything
~~~
练习
添加Python约束
增加一个约束,检查,教练是不出席在他/她自己的会议出席。
*openacademy/models.py*
~~~ python
# -*- coding: utf-8 -*-
from openerp import models, fields, api, exceptions
class Course(models.Model):
_name = 'openacademy.course'
~~~
~~~ python
'message': "Increase seats or remove excess attendees",
},
}
@api.constrains('instructor_id', 'attendee_ids')
def _check_instructor_not_in_attendees(self):
for r in self:
if r.instructor_id and r.instructor_id in r.attendee_ids:
raise exceptions.ValidationError("A session's instructor can't be an attendee")
~~~
SQL约束是通过模型的属性定义 [`_sql_constraints`](https://www.odoo.com/documentation/9.0/reference/orm.html#openerp.models.Model._sql_constraints "openerp.models.Model._sql_constraints"). 后者是分配到一个列表中的字符串`三元组(名称、sql_definition,消息)`,当`名字`是一个有效的SQL约束的名字,` sql_definition `是 [table_constraint](http://www.postgresql.org/docs/9.3/static/ddl-constraints.html)表达式,和“消息”是错误消息。
练习
添加SQL约束
在 [PostgreSQL的文档](http://www.postgresql.org/docs/9.3/static/ddl-constraints.html) 帮助下 , 添加以下约束:
1. 检查课程简介和课程名称是不同的
2. 使课程名称唯一
*openacademy/models.py*
~~~ python
session_ids = fields.One2many(
'openacademy.session', 'course_id', string="Sessions")
_sql_constraints = [
('name_description_check',
'CHECK(name != description)',
"The title of the course should not be the description"),
('name_unique',
'UNIQUE(name)',
"The course title must be unique"),
]
class Session(models.Model):
_name = 'openacademy.session'
~~~
练习
练习6 -添加一个重复的选项
因为我们在课程名称的唯一性上增加了一个约束,不可能使用“复制”功能(重复)。
重新实现您自己的“复制”方法,它允许复制的课程对象,将原来的名字改为“复制[原名称]”。
*openacademy/models.py*
~~~ python
session_ids = fields.One2many(
'openacademy.session', 'course_id', string="Sessions")
@api.multi
def copy(self, default=None):
default = dict(default or {})
copied_count = self.search_count(
[('name', '=like', u"Copy of {}%".format(self.name))])
if not copied_count:
new_name = u"Copy of {}".format(self.name)
else:
new_name = u"Copy of {} ({})".format(self.name, copied_count)
default['name'] = new_name
return super(Course, self).copy(default)
_sql_constraints = [
('name_description_check',
'CHECK(name != description)',
~~~