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ờ)

DatesDatetimes 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ặc datetime.

  • Một chuỗi ở định dạng máy chủ thích hợp:

    • YYYY-MM-DD cho các trường Date,

    • YYYY-MM-DD HH:MM:SS cho các trường Datetime.

  • Sai hoặc Khô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:

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ả DateDatetime. 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 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 quan

    document = 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 web

Theo 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ào res.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ành res.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ên fields.

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_ofparent_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_ofparent_of trong tìm kiếm tên miền. Nó phải được khai báo bằng index=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()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ới value. 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 valueNone hoặc False, nếu không thì hoạt động như =)

    =thích

    khớp field_name với mẫu value. 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ọc value bằng '%' trước khi khớp

    khô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ục

    khô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, or Many2many) satisfies the provided domain value.

    not any

    matches if no record in the relationship traversal through field_name (Many2one, One2many, or Many2many) satisfies the provided domain value.

  • 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)])]

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 trong set hay không. bản ghi không trong tập hợp là phép toán nghịch đảo

  • set1 <= set2set1 < set2 trả về xem set1 có phải là tập con của set2 hay không (resp. strict)

  • set1 >= set2set1 > set2 trả về xem set1 có phải là tập hợp con của set2 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ồn

  • set1 & 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ồn

  • set1 - set2 trả về một tập bản ghi mới chỉ chứa các bản ghi của set1 không trong set2

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 đó

../../../_images/inheritance_methods.png

Kế thừa cổ điển

Khi sử dụng các thuộc tính _inherit_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")

Quản lý lỗi