API ORM¶
Người mẫu¶
Các trường mô hình được định nghĩa là các thuộc tính trên chính mô hình đó
from odoo import models, fields
class AModel(models.Model):
_name = 'a.model.name'
field1 = fields.Char()
Cảnh báo
điều này có nghĩa là bạn không thể xác định trường và phương thức có cùng tên, trường cuối cùng sẽ âm thầm ghi đè lên trường cũ.
Theo mặc định, nhãn của trường (tên hiển thị cho người dùng) là phiên bản viết hoa của tên trường, điều này có thể được ghi đè bằng tham số string
.
field2 = fields.Integer(string="Field Label")
Để biết danh sách các loại trường và tham số, hãy xem the field reference.
Giá trị mặc định được xác định là tham số trên các trường, dưới dạng giá trị
name = fields.Char(default="a value")
hoặc như một hàm được gọi để tính giá trị mặc định, giá trị này sẽ trả về giá trị đó
def _default_name(self):
return self.get_value()
name = fields.Char(default=lambda self: self._default_name())
API
Tóm tắtMô hình¶
Người mẫu¶
thoáng quaModel¶
Lĩnh vực¶
Các trường cơ bản¶
Trường nâng cao¶
Các trường ngày (giờ)¶
Dates
và Datetimes
là các trường rất quan trọng trong bất kỳ loại ứng dụng kinh doanh nào. Việc sử dụng sai mục đích của chúng có thể tạo ra các lỗi vô hình nhưng gây đau đớn, phần này nhằm mục đích cung cấp cho các nhà phát triển SoOn kiến thức cần thiết để tránh lạm dụng các lĩnh vực này.
Khi gán giá trị cho trường Ngày/Ngày, các tùy chọn sau là hợp lệ:
Đối tượng
date
hoặcdatetime
.Một chuỗi ở định dạng máy chủ thích hợp:
YYYY-MM-DD
cho các trườngDate
,YYYY-MM-DD HH:MM:SS
cho các trườngDatetime
.
Sai
hoặcKhông
.
Lớp trường Ngày và Giờ có các phương thức trợ giúp để cố gắng chuyển đổi thành loại tương thích:
to_date()
sẽ chuyển đổi thànhdatetime.date
to_datetime()
sẽ chuyển đổi thànhdatetime.datetime
.
Example
Để phân tích ngày/giờ đến từ các nguồn bên ngoài
fields.Date.to_date(self._context.get('date_from'))
Các phương pháp hay nhất về so sánh ngày/giờ:
Các trường ngày chỉ có thể được so sánh với các đối tượng ngày.
Các trường ngày giờ chỉ có thể được so sánh với các đối tượng ngày giờ.
Cảnh báo
Các chuỗi biểu thị ngày và giờ có thể được so sánh với nhau, tuy nhiên, kết quả có thể không như mong đợi vì chuỗi ngày giờ sẽ luôn lớn hơn chuỗi ngày, do đó cách làm này rất không được khuyến khích.
Các hoạt động phổ biến với ngày và giờ như cộng, trừ hoặc tìm nạp phần đầu/cuối của một khoảng thời gian được hiển thị thông qua cả Date
và Datetime
. Những trợ giúp này cũng có sẵn bằng cách nhập odoo.tools.date_utils
.
Ghi chú
Múi giờ
Các trường ngày giờ được lưu trữ dưới dạng cột dấu thời gian không có múi giờ
trong cơ sở dữ liệu và được lưu trữ trong múi giờ UTC. Đây là do thiết kế vì nó làm cho cơ sở dữ liệu SoOn độc lập với múi giờ của hệ thống máy chủ lưu trữ. Việc chuyển đổi múi giờ được quản lý hoàn toàn bởi phía khách hàng.
Trường quan hệ¶
Trường giả quan hệ¶
Trường tính toán¶
Các trường có thể được tính toán (thay vì đọc trực tiếp từ cơ sở dữ liệu) bằng cách sử dụng tham số compute
. Nó phải gán giá trị được tính toán cho trường. Nếu nó sử dụng giá trị của các trường khác, thì nó phải chỉ định các trường đó bằng cách sử dụng depends()
.
from odoo import api
total = fields.Float(compute='_compute_total')
@api.depends('value', 'tax')
def _compute_total(self):
for record in self:
record.total = record.value + record.value * record.tax
phần phụ thuộc có thể là các đường dẫn chấm khi sử dụng các trường con:
@api.depends('line_ids.value') def _compute_total(self): for record in self: record.total = sum(line.value for line in record.line_ids)
các trường được tính toán không được lưu trữ theo mặc định, chúng được tính toán và trả về khi được yêu cầu. Cài đặt
store=True
sẽ lưu trữ chúng trong cơ sở dữ liệu và tự động kích hoạt tìm kiếm.tìm kiếm trên trường được tính toán cũng có thể được bật bằng cách đặt tham số
search
. Giá trị là tên phương thức trả về Tìm kiếm tên miền.upper_name = field.Char(compute='_compute_upper', search='_search_upper') def _search_upper(self, operator, value): if operator == 'like': operator = 'ilike' return [('name', operator, value)]
Phương thức tìm kiếm được gọi khi xử lý các miền trước khi thực hiện tìm kiếm thực tế trên mô hình. Nó phải trả về một miền tương đương với điều kiện:
giá trị toán tử trường
.
Các trường được tính toán theo mặc định là chỉ đọc. Để cho phép các giá trị setting trên trường được tính toán, hãy sử dụng tham số
inverse
. Đó là tên của một hàm đảo ngược tính toán và thiết lập các trường có liên quandocument = fields.Char(compute='_get_document', inverse='_set_document') def _get_document(self): for record in self: with open(record.get_document_path) as f: record.document = f.read() def _set_document(self): for record in self: if not record.document: continue with open(record.get_document_path()) as f: f.write(record.document)
nhiều trường có thể được tính toán cùng lúc bằng cùng một phương pháp, chỉ cần sử dụng cùng một phương thức trên tất cả các trường và đặt tất cả chúng
discount_value = fields.Float(compute='_apply_discount') total = fields.Float(compute='_apply_discount') @api.depends('value', 'discount') def _apply_discount(self): for record in self: # compute actual discount from discount percentage discount = record.value * record.discount record.discount_value = discount record.total = record.value - discount
Cảnh báo
Mặc dù có thể sử dụng cùng một phương pháp tính toán cho nhiều trường nhưng bạn không nên thực hiện tương tự cho phương pháp nghịch đảo.
Trong quá trình tính toán nghịch đảo, tất cả các trường sử dụng nghịch đảo nói trên đều được bảo vệ, nghĩa là chúng không thể được tính toán, ngay cả khi giá trị của chúng không có trong bộ đệm.
Nếu bất kỳ trường nào trong số đó được truy cập và giá trị của nó không có trong bộ đệm, ORM sẽ chỉ trả về giá trị mặc định là False
cho các trường này. Điều này có nghĩa là giá trị của các trường nghịch đảo (không phải trường kích hoạt phương thức nghịch đảo) có thể không cho giá trị chính xác và điều này có thể sẽ phá vỡ hành vi mong đợi của phương pháp nghịch đảo.
Trường tự động¶
- Model.id¶
Mã định danh
field
Nếu độ dài của tập bản ghi hiện tại là 1, trả về id của bản ghi duy nhất trong đó.
Nếu không thì sẽ báo lỗi.
- Model.display_name¶
Tên
field
được hiển thị theo mặc định trong máy khách webTheo mặc định, nó bằng với trường giá trị
_rec_name
nhưng hành vi có thể được tùy chỉnh bằng cách ghi đè_compute_display_name
Truy cập các trường Nhật ký¶
Các trường này được tự động đặt và cập nhật nếu _log_access
được bật. Nó có thể bị vô hiệu hóa để tránh tạo hoặc cập nhật các trường đó trên các bảng mà chúng không hữu ích.
Theo mặc định, _log_access
được đặt thành cùng giá trị với _auto
- Model.create_date¶
Lưu trữ thời điểm bản ghi được tạo,
Datetime
- Model.create_uid¶
Lưu trữ người đã tạo bản ghi,
Many2one
vàores.users
.
- Model.write_date¶
Lưu trữ thời điểm bản ghi được cập nhật lần cuối,
Datetime
- Model.write_uid¶
Cửa hàng đã cập nhật bản ghi lần cuối,
Many2one
thànhres.users
.
Cảnh báo
_log_access
phải được bật trên TransientModel
.
Tên trường dành riêng¶
Một số tên trường được dành riêng cho các hành vi được xác định trước ngoài các trường tự động. Chúng nên được xác định trên một mô hình khi mong muốn có hành vi liên quan:
- Model.name¶
giá trị mặc định cho
_rec_name
, được sử dụng để hiển thị các bản ghi trong ngữ cảnh cần phải "đặt tên" đại diện.Char
- Model.active¶
chuyển đổi chế độ hiển thị chung của bản ghi, nếu `` hoạt động`` được đặt thành `` Sai`` thì bản ghi sẽ không hiển thị trong hầu hết các tìm kiếm và danh sách.
Boolean
Các phương pháp đặc biệt:
- Model.state¶
các giai đoạn vòng đời của đối tượng, được sử dụng bởi thuộc tính
states
trênfields
.Selection
- Model.parent_id¶
default_value của
_parent_name
, dùng để sắp xếp các bản ghi theo cấu trúc cây và kích hoạt các toán tửchild_of
vàparent_of
trong các miền.Many2one
- Model.parent_path¶
Khi
_parent_store
được đặt thành True, dùng để lưu trữ giá trị phản ánh cấu trúc cây của_parent_name
và để tối ưu hóa các toán tửchild_of
vàparent_of
trong tìm kiếm tên miền. Nó phải được khai báo bằngindex=True
để hoạt động chính xác.Char
- Model.company_id¶
Tên trường chính được sử dụng cho hành vi đa công ty của SoOn.
Được sử dụng bởi
:meth:~odoo.models._check_company
để kiểm tra tính nhất quán của nhiều công ty. Xác định liệu một bản ghi có được chia sẻ giữa các công ty hay không (không có giá trị) hay chỉ người dùng của một công ty nhất định mới có thể truy cập được.Many2one
:type:res_company
Bộ ghi âm¶
Tương tác với các mô hình và bản ghi được thực hiện thông qua các tập bản ghi, một tập hợp các bản ghi được sắp xếp theo thứ tự của cùng một mô hình.
Cảnh báo
Ngược lại với ý nghĩa của tên gọi, hiện tại các tập bản ghi có thể chứa các bản sao. Nó có thể thay đổi tương lai.
Các phương thức được xác định trên một mô hình được thực thi trên một tập bản ghi và self
của chúng là một tập bản ghi:
class AModel(models.Model):
_name = 'a.model'
def a_method(self):
# self can be anything between 0 records and all records in the
# database
self.do_operation()
Việc lặp lại trên một tập bản ghi sẽ tạo ra các tập hợp mới gồm một bản ghi ("singleton"), giống như việc lặp lại trên một chuỗi Python mang lại các chuỗi gồm một ký tự đơn:
def do_operation(self):
print(self) # => a.model(1, 2, 3, 4, 5)
for record in self:
print(record) # => a.model(1), then a.model(2), then a.model(3), ...
Truy cập trường¶
Bộ bản ghi cung cấp giao diện "Bản ghi hoạt động": các trường mô hình có thể được đọc và ghi trực tiếp từ bản ghi dưới dạng thuộc tính.
Ghi chú
Khi truy cập các trường không quan hệ trên tập bản ghi có khả năng có nhiều bản ghi, hãy sử dụng mapped()
:
total_qty = sum(self.mapped('qty'))
Các giá trị trường cũng có thể được truy cập như các mục dict, thanh lịch hơn và an toàn hơn getattr()
đối với tên trường động. Việc đặt giá trị của trường sẽ kích hoạt cập nhật cơ sở dữ liệu
>>> record.name
Example Name
>>> record.company_id.name
Company Name
>>> record.name = "Bob"
>>> field = "name"
>>> record[field]
Bob
Cảnh báo
Cố gắng đọc một trường trên nhiều bản ghi sẽ gây ra lỗi đối với các trường không quan hệ.
Truy cập một trường quan hệ (Many2one
, One2many
, Many2many
) luôn trả về một tập bản ghi, trống nếu trường này chưa được thiết lập.
Ghi lại bộ nhớ đệm và tìm nạp trước¶
SoOn duy trì một bộ đệm cho các trường của bản ghi, do đó không phải mọi quyền truy cập vào trường đều đưa ra yêu cầu cơ sở dữ liệu, điều này sẽ gây ảnh hưởng xấu đến hiệu suất. Ví dụ sau chỉ truy vấn cơ sở dữ liệu cho câu lệnh đầu tiên:
record.name # first access reads value from database
record.name # second access gets value from cache
Để tránh đọc từng trường trên một bản ghi, SoOn tìm nạp trước bản ghi và các trường theo một số phương pháp phỏng đoán để có được hiệu suất tốt. Khi một trường phải được đọc trên một bản ghi nhất định, ORM sẽ thực sự đọc trường đó trên một tập bản ghi lớn hơn và lưu trữ các giá trị trả về trong bộ đệm để sử dụng sau. Tập bản ghi được tìm nạp trước thường là tập bản ghi mà từ đó bản ghi được lặp lại. Hơn nữa, tất cả các trường được lưu trữ đơn giản (boolean, số nguyên, float, char, văn bản, ngày, datetime, vùng chọn, many2one) đều được tìm nạp hoàn toàn; chúng tương ứng với các cột trong bảng của mô hình và được tìm nạp một cách hiệu quả trong cùng một truy vấn.
Hãy xem xét ví dụ sau, trong đó partners
là tập bản ghi gồm 1000 bản ghi. Nếu không tìm nạp trước, vòng lặp sẽ thực hiện 2000 truy vấn tới cơ sở dữ liệu. Với tìm nạp trước, chỉ có một truy vấn được thực hiện:
for partner in partners:
print partner.name # first pass prefetches 'name' and 'lang'
# (and other fields) on all 'partners'
print partner.lang
Tính năng tìm nạp trước cũng hoạt động trên bản ghi phụ: khi các trường quan hệ được đọc, giá trị của chúng (là bản ghi) sẽ được đăng ký để tìm nạp trước trong tương lai. Việc truy cập vào một trong các bản ghi phụ đó sẽ tìm nạp trước tất cả các bản ghi phụ từ cùng một mô hình. Điều này khiến ví dụ sau chỉ tạo ra hai truy vấn, một cho đối tác và một cho các quốc gia:
countries = set()
for partner in partners:
country = partner.country_id # first pass prefetches all partners
countries.add(country.name) # first pass prefetches all countries
Xem thêm
Các phương thức search_fetch()
và fetch()
có thể được sử dụng để điền vào bộ đệm của các bản ghi, thường là trong trường hợp cơ chế tìm nạp trước không hoạt động tốt .
Phương pháp trang trí¶
Môi trường¶
>>> records.env
<Environment object ...>
>>> records.env.uid
3
>>> records.env.user
res.user(3)
>>> records.env.cr
<Cursor object ...>
Khi tạo một tập bản ghi từ một tập bản ghi khác, môi trường sẽ được kế thừa. Môi trường có thể được sử dụng để lấy tập bản ghi trống trong một mô hình khác và truy vấn mô hình đó:
>>> self.env['res.partner']
res.partner()
>>> self.env['res.partner'].search([('is_company', '=', True), ('customer', '=', True)])
res.partner(7, 18, 12, 14, 17, 19, 8, 31, 26, 16, 13, 20, 30, 22, 29, 15, 23, 28, 74)
Một số thuộc tính lười biếng có sẵn để truy cập dữ liệu môi trường (theo ngữ cảnh):
Phương pháp môi trường hữu ích¶
Thay đổi môi trường¶
Thực thi SQL¶
Thuộc tính cr
trên môi trường là con trỏ cho giao dịch cơ sở dữ liệu hiện tại và cho phép thực thi SQL trực tiếp, đối với các truy vấn khó diễn đạt bằng ORM (ví dụ: các phép nối phức tạp) hoặc để thực hiện lý do:
self.env.cr.execute("some_sql", params)
Cảnh báo
Việc thực thi SQL thô sẽ bỏ qua ORM và do đó, các quy tắc bảo mật của SoOn sẽ bỏ qua. Vui lòng đảm bảo rằng các truy vấn của bạn được làm sạch khi sử dụng đầu vào của người dùng và ưu tiên sử dụng các tiện ích ORM nếu bạn không thực sự cần sử dụng các truy vấn SQL.
Cách được khuyến nghị để xây dựng các truy vấn SQL là sử dụng đối tượng trình bao bọc
Một điều quan trọng cần biết về mô hình là chúng không nhất thiết phải thực hiện cập nhật cơ sở dữ liệu ngay lập tức. Thật vậy, vì lý do hiệu suất, khung này trì hoãn việc tính toán lại các trường sau khi sửa đổi bản ghi. Và một số cập nhật cơ sở dữ liệu cũng bị trì hoãn. Do đó, trước khi truy vấn cơ sở dữ liệu, người ta phải đảm bảo rằng nó chứa dữ liệu liên quan cho truy vấn. Thao tác này được gọi là xả và thực hiện các cập nhật cơ sở dữ liệu dự kiến.
Example
# make sure that 'partner_id' is up-to-date in database
self.env['model'].flush_model(['partner_id'])
self.env.cr.execute(SQL("SELECT id FROM model WHERE partner_id IN %s", ids))
ids = [row[0] for row in self.env.cr.fetchall()]
Trước mỗi truy vấn SQL, người ta phải xóa dữ liệu cần thiết cho truy vấn đó. Có ba cấp độ để xả, mỗi cấp độ có API riêng. Người ta có thể xóa mọi thứ, tất cả các bản ghi của một mô hình hoặc một số bản ghi cụ thể. Vì việc trì hoãn cập nhật sẽ cải thiện hiệu suất nói chung nên chúng tôi khuyên bạn nên cụ thể khi xóa.
Vì các mô hình sử dụng cùng một con trỏ và Environment
chứa nhiều bộ nhớ đệm khác nhau nên các bộ nhớ đệm này phải bị vô hiệu hóa khi thay đổi cơ sở dữ liệu trong SQL thô, nếu không việc sử dụng thêm các mô hình có thể trở nên không mạch lạc. Cần phải xóa bộ nhớ đệm khi sử dụng CREATE
, UPDATE
hoặc DELETE
trong SQL, chứ không phải SELECT
(chỉ đơn giản là đọc cơ sở dữ liệu).
Example
# make sure 'state' is up-to-date in database
self.env['model'].flush_model(['state'])
self.env.cr.execute("UPDATE model SET state=%s WHERE state=%s", ['new', 'old'])
# invalidate 'state' from the cache
self.env['model'].invalidate_model(['state'])
Cũng giống như xóa, người ta có thể vô hiệu hóa toàn bộ bộ đệm, bộ đệm của tất cả các bản ghi của một mô hình hoặc bộ đệm của các bản ghi cụ thể. Người ta thậm chí có thể vô hiệu hóa các trường cụ thể trên một số bản ghi hoặc tất cả bản ghi của một mô hình. Vì bộ nhớ đệm cải thiện hiệu suất nói chung nên chúng tôi khuyên bạn nên cụ thể khi vô hiệu hóa.
Các phương pháp trên giữ cho bộ đệm và cơ sở dữ liệu nhất quán với nhau. Tuy nhiên, nếu các phần phụ thuộc của trường được tính toán đã được sửa đổi trong cơ sở dữ liệu, người ta phải thông báo cho các mô hình về các trường được tính toán sẽ được tính toán lại. Điều duy nhất mà khung cần biết là các trường what đã thay đổi trên bản ghi * which*.
Example
# make sure 'state' is up-to-date in database
self.env['model'].flush_model(['state'])
# use the RETURNING clause to retrieve which rows have changed
self.env.cr.execute("UPDATE model SET state=%s WHERE state=%s RETURNING id", ['new', 'old'])
ids = [row[0] for row in self.env.cr.fetchall()]
# invalidate the cache, and notify the update to the framework
records = self.env['model'].browse(ids)
records.invalidate_recordset(['state'])
records.modified(['state'])
Người ta phải tìm ra hồ sơ nào đã được sửa đổi. Có nhiều cách để thực hiện việc này, có thể liên quan đến các truy vấn SQL bổ sung. Trong ví dụ trên, chúng tôi tận dụng mệnh đề RETURNING
của PostgreSQL để lấy thông tin mà không cần truy vấn thêm. Sau khi làm cho bộ đệm nhất quán bằng cách vô hiệu hóa, hãy gọi phương thức `` đã sửa đổi`` trên các bản ghi đã sửa đổi với các trường đã được cập nhật.
Các phương pháp ORM phổ biến¶
Tạo/cập nhật¶
Tìm kiếm/Đọc¶
Lĩnh vực¶
Tìm kiếm tên miền¶
Miền là một danh sách các tiêu chí, mỗi tiêu chí là một bộ ba (có thể là danh sách
hoặc tuple
) của (field_name, operator, value)
trong đó:
tên_trường
(str
)tên trường của mô hình hiện tại hoặc truyền tải mối quan hệ thông qua
Many2one
bằng cách sử dụng ký hiệu dấu chấm, ví dụ:'đường phố'
hoặc'partner_id.country'
toán tử
(str
)một toán tử dùng để so sánh
field_name
vớivalue
. Các toán tử hợp lệ là:=
tương đương với
!=
không bằng
>
lớn hơn
>=
lớn hơn hoặc bằng
<
ít hơn
<=
ít hơn hoặc bằng
=?
không được đặt hoặc bằng (trả về true nếu
value
làNone
hoặcFalse
, nếu không thì hoạt động như=
)=thích
khớp
field_name
với mẫuvalue
. Dấu gạch dưới_
trong mẫu là viết tắt của (khớp) bất kỳ ký tự đơn nào; dấu phần trăm%
khớp với bất kỳ chuỗi nào có 0 hoặc nhiều ký tự.thích
khớp
field_name
với mẫu%value%
. Tương tự như=like
nhưng bao bọcvalue
bằng '%' trước khi khớpkhông thích
không khớp với mẫu
%value%
thích
không phân biệt chữ hoa chữ thường `` like``
không thích
không phân biệt chữ hoa chữ thường
không thích
=thích
không phân biệt chữ hoa chữ thường
=like
- `` trong``
bằng bất kỳ mục nào trong
value
,value
phải là danh sách các mụckhông ở
không bằng tất cả các mục từ `` value``
con_of
là con (hậu duệ) của bản ghi
giá trị
(giá trị có thể là một mục hoặc danh sách các mục).Có tính đến ngữ nghĩa của mô hình (tức là tuân theo trường mối quan hệ được đặt tên bởi
_parent_name
).cha mẹ của
là cha (tăng dần) của bản ghi
giá trị
(giá trị có thể là một mục hoặc danh sách các mục).Có tính đến ngữ nghĩa của mô hình (tức là tuân theo trường mối quan hệ được đặt tên bởi
_parent_name
).any
matches if any record in the relationship traversal through
field_name
(Many2one
,One2many
, orMany2many
) satisfies the provided domainvalue
.not any
matches if no record in the relationship traversal through
field_name
(Many2one
,One2many
, orMany2many
) satisfies the provided domainvalue
.
giá trị
loại biến, phải có thể so sánh được (thông qua
toán tử
) với trường được đặt tên.
Tiêu chí tên miền có thể được kết hợp bằng cách sử dụng toán tử logic ở dạng tiền tố:
'&'
logic AND, thao tác mặc định để kết hợp các tiêu chí nối tiếp nhau. Loại 2 (sử dụng 2 tiêu chí hoặc kết hợp tiếp theo).
'|'
logic HOẶC, giá trị 2.
'!'
logic KHÔNG, giá trị 1.
Ghi chú
Chủ yếu là để phủ định các kết hợp tiêu chí Tiêu chí riêng lẻ thường có dạng phủ định (ví dụ:
=
->!=
,<
->>=
) đơn giản hơn phủ định tích cực .
Example
To search for partners named ABC, with a phone or mobile number containing 7620:
[('name', '=', 'ABC'),
'|', ('phone','ilike','7620'), ('mobile', 'ilike', '7620')]
To search sales orders to invoice that have at least one line with a product that is out of stock:
[('invoice_status', '=', 'to invoice'),
('order_line', 'any', [('product_id.qty_available', '<=', 0)])]
Hủy liên kết¶
Thông tin bản ghi (bộ)¶
- odoo.models.env¶
Trả về môi trường của recordset đã cho.
- kiểu
Environment
Hoạt động¶
Các tập bản ghi là bất biến, nhưng các tập hợp của cùng một mô hình có thể được kết hợp bằng nhiều thao tác tập hợp khác nhau, trả về các tập bản ghi mới.
bản ghi trong tập hợp
trả về xem `` bản ghi`` (phải là tập bản ghi 1 phần tử) có hiện diện trongset
hay không.bản ghi không có trong tập hợp
là phép toán nghịch đảoset1 <= set2
vàset1 < set2
trả về xemset1
có phải là tập con củaset2
hay không (resp. strict)set1 >= set2
vàset1 > set2
trả về xemset1
có phải là tập hợp con củaset2
hay không (tương ứng nghiêm ngặt)set1 | set2
trả về sự kết hợp của hai tập bản ghi, một tập bản ghi mới chứa tất cả các bản ghi có trong một trong hai nguồnset1 & set2
trả về giao điểm của hai tập bản ghi, một tập bản ghi mới chỉ chứa các bản ghi có trong cả hai nguồnset1 - set2
trả về một tập bản ghi mới chỉ chứa các bản ghi củaset1
không trongset2
Các tập bản ghi có thể lặp lại nên các công cụ Python thông thường có sẵn để chuyển đổi (map()
, sorted()
, ifilter()
, ...) tuy nhiên chúng trả về list
hoặc iterator, loại bỏ khả năng gọi các phương thức trên kết quả của chúng hoặc sử dụng các thao tác thiết lập.
Do đó, các tập bản ghi cung cấp các thao tác trả về các tập bản ghi sau đây (khi có thể):
Lọc¶
Bản đồ¶
Ghi chú
Kể từ V13, quyền truy cập trường đa quan hệ được hỗ trợ và hoạt động giống như một cuộc gọi được ánh xạ:
records.partner_id # == records.mapped('partner_id')
records.partner_id.bank_ids # == records.mapped('partner_id.bank_ids')
records.partner_id.mapped('name') # == records.mapped('partner_id.name')
Loại¶
Nhóm¶
Kế thừa và mở rộng¶
SoOn cung cấp ba cơ chế khác nhau để mở rộng mô hình theo mô-đun:
tạo một mô hình mới từ một mô hình hiện có, thêm thông tin mới vào bản sao nhưng vẫn giữ nguyên mô-đun gốc
mở rộng các mô hình được xác định trong các mô-đun khác tại chỗ, thay thế phiên bản trước đó
ủy quyền một số trường của mô hình cho các bản ghi chứa trong đó

Kế thừa cổ điển¶
Khi sử dụng các thuộc tính _inherit
và _name
cùng nhau, SoOn sẽ tạo một mô hình mới bằng cách sử dụng mô hình hiện có (được cung cấp qua _inherit
) làm cơ sở. Mô hình mới lấy tất cả các trường, phương thức và thông tin meta (mặc định & al) từ cơ sở của nó.
class Inheritance0(models.Model):
_name = 'inheritance.0'
_description = 'Inheritance Zero'
name = fields.Char()
def call(self):
return self.check("model 0")
def check(self, s):
return "This is {} record {}".format(s, self.name)
class Inheritance1(models.Model):
_name = 'inheritance.1'
_inherit = 'inheritance.0'
_description = 'Inheritance One'
def call(self):
return self.check("model 1")
và sử dụng chúng:
a = env['inheritance.0'].create({'name': 'A'})
b = env['inheritance.1'].create({'name': 'B'})
a.call()
b.call()
sẽ mang lại:
"Đây là bản ghi mẫu 0 A" "Đây là bản ghi mẫu 1 B"
mô hình thứ hai đã kế thừa từ phương thức check
của mô hình đầu tiên và trường name
của nó, nhưng được ghi đè phương thức call
, như khi sử dụng Python kế thừa.
Sự mở rộng¶
Khi sử dụng _inherit
nhưng bỏ đi _name
, mô hình mới sẽ thay thế mô hình hiện có, về cơ bản là mở rộng mô hình tại chỗ. Điều này hữu ích khi thêm các trường hoặc phương thức mới vào các mô hình hiện có (được tạo trong các mô-đun khác) hoặc để tùy chỉnh hoặc định cấu hình lại chúng (ví dụ: để thay đổi thứ tự sắp xếp mặc định của chúng):
class Extension0(models.Model):
_name = 'extension.0'
_description = 'Extension zero'
name = fields.Char(default="A")
class Extension1(models.Model):
_inherit = 'extension.0'
description = fields.Char(default="Extended")
record = env['extension.0'].create({})
record.read()[0]
sẽ mang lại:
{'name': "A", 'description': "Extended"}
Ghi chú
Nó cũng sẽ mang lại nhiều các trường tự động trừ khi chúng bị vô hiệu hóa
Phái đoàn¶
Cơ chế kế thừa thứ ba cung cấp tính linh hoạt cao hơn (nó có thể được thay đổi trong thời gian chạy) nhưng ít năng lượng hơn: sử dụng _inherits
một mô hình đại biểu tra cứu bất kỳ trường nào không tìm thấy trên mô hình hiện tại đến những người mẫu "trẻ em". Việc ủy quyền được thực hiện thông qua các trường Reference
được thiết lập tự động trên mô hình gốc.
Sự khác biệt chính là ở ý nghĩa. Khi sử dụng Delegation, mô hình has one thay vì is one, chuyển mối quan hệ trong một thành phần thay vì kế thừa:
class Screen(models.Model):
_name = 'delegation.screen'
_description = 'Screen'
size = fields.Float(string='Screen Size in inches')
class Keyboard(models.Model):
_name = 'delegation.keyboard'
_description = 'Keyboard'
layout = fields.Char(string='Layout')
class Laptop(models.Model):
_name = 'delegation.laptop'
_description = 'Laptop'
_inherits = {
'delegation.screen': 'screen_id',
'delegation.keyboard': 'keyboard_id',
}
name = fields.Char(string='Name')
maker = fields.Char(string='Maker')
# a Laptop has a screen
screen_id = fields.Many2one('delegation.screen', required=True, ondelete="cascade")
# a Laptop has a keyboard
keyboard_id = fields.Many2one('delegation.keyboard', required=True, ondelete="cascade")
record = env['delegation.laptop'].create({
'screen_id': env['delegation.screen'].create({'size': 13.0}).id,
'keyboard_id': env['delegation.keyboard'].create({'layout': 'QWERTY'}).id,
})
record.size
record.layout
sẽ cho kết quả:
13.0
'QWERTY'
và có thể viết trực tiếp trên trường được ủy quyền
record.write({'size': 14.0})
Cảnh báo
khi sử dụng tính kế thừa ủy quyền, các phương thức không được kế thừa, chỉ các trường
Cảnh báo
_inherits
ít nhiều được triển khai, hãy tránh nó nếu bạn có thể;_inherits
bị xích về cơ bản không được triển khai, chúng tôi không thể đảm bảo bất cứ điều gì về hành vi cuối cùng.
Định nghĩa tăng dần của trường¶
Một trường được định nghĩa là thuộc tính lớp trên một lớp mô hình. Nếu mô hình được mở rộng, người ta cũng có thể mở rộng định nghĩa trường bằng cách xác định lại trường có cùng tên và cùng loại trên lớp con. Trong trường hợp đó, các thuộc tính của trường được lấy từ lớp cha và được ghi đè bởi các thuộc tính được đưa ra trong lớp con.
Chẳng hạn, lớp thứ hai bên dưới chỉ thêm chú giải công cụ vào trường state
:
class First(models.Model):
_name = 'foo'
state = fields.Selection([...], required=True)
class Second(models.Model):
_inherit = 'foo'
state = fields.Selection(help="Blah blah blah")