## 模型約束
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)',
~~~