Odoo 14 - Application Models
Odoo 14 - Application Models
#4
• Application Models
Pembahasan :
Definisi Model Representation dan Order
Menambahkan Field Data ke sebuah Model
Float Field dengan tingkat presisi (precision)
Menambahkan Monetary Field ke sebuah Model
Menambahkan Relational Field ke sebuah Model
Menambahkan Hirarki ke sebuah Model
Menambahkan Constraint Validation ke sebuah Model
Menambahkan Computed Fields ke sebuah Model
Menampilkan Related Fields yang disimpan di Model Lain
Menambahkan Relasi Dinamis menggunakan Reference Fields
Menambahkan Fitur baru ke sebuah model menggunakan Inheritance
Menggunakan Abstract Models untuk Fitur Reusable Model
Menggunakan Delegation Inheritance utk Copy Fitur ke model lain
Konfigurasi odoo.conf
https://github.com/PacktPublishing/Odoo-14-Development-
Cookbook-Fourth-Edition/tree/master/Chapter04
• Attribute dalam Models:
• _name : nama tabel dalam database, harus unique dalam
aplikasi Odoo database
• _rec_name : nama field yang digunakan sebagai
representasi / title record (biasanya dipakai untuk
menggantikan field name )
• _order : Untuk menampilkan urutan record
• _description : Judul model/tabel untuk memudahkan
• Warning:
• Jika sebuah model tidak memiliki field dg nama name dan
kita tidak mendefinisikan _rec_name maka nama yang
tampil (display name) adalah kombinasi nama model dan
record ID contoh :
Models library.book,1
• Tambahan Info :
• Ada sebuah method name_get() yang secara default
menampilkan display name dengan _rec_name. Jika ingin
menampilkan secara custom, maka kita harus melakukan
override method name_get()
Contoh implementasi name_get()
def name_get(self):
result = []
for record in self:
rec_name = "%s (%s)" % (record.name, record.date_release)
result.append((record.id, rec_name))
return result
Untuk Field dengan tipe Float, kita bisa melakukan konfigurasi untuk
decimal precision nya :
• Activate Developer Mode
• Setting – Technical – Database Structure – Decimal Accuracy
• Buat konfigurasi baru, misal : Usage = Book Price dan pilih digit
precision
• Lakukan edit di models, tambahkan di field ber tipe Float dengan
Models: attribute
digits=‘Book Price’
Field Attribute
class LibraryBook(models.Model):
cost_price = fields.Float('Book Cost', digits='Book Price')
class LibraryBook(models.Model):
# ...
currency_id = fields.Many2one('res.currency’, string='Currency')
class LibraryBook(models.Model):
# ...
retail_price = field.Monetary(
‘Retail Price’,
Monetary Field # optional: currency_field=‘currency_id’,
)
Relational Field di Odoo ada 3 macam :
1. many-to-one, biasanya disingkat m2o
2. one-to-many, biasanya disingkat o2m
3. many-to-many, biasanya disingkat m2m
class LibraryBook(models.Model):
# ...
publisher_id = fields.Many2one(‘res.partner’, string=‘Publisher’,
#optional:
ondelete = ‘set null’,
context={}
domain=[]
)
Models: Untuk relasi one2many bisa digambarkan dari hubungan partner dan
class ResPartner(models.Model):
_inherit = ‘res.partner’
published_book_ids = fields.One2many(
‘library.book’, ‘publisher_id’,
string=‘Published Books’)
PENJELASAN :
• Many-to-One Field akan menambah kolom field di tabel dan
menyimpan ID dari record yang terkait
• Pada level Database, constraint foreign key juga otomatis dibuat untuk
memastikan ID yang tersimpan valid dan ber-relasi dengan tabel relasi.
• Tidak ada index terbentuk secara otomatis, kecuali kita tambahkan
attribute index=True
• Attribute ondelete menentukan apa yang terjadi jika record yang ter-
relasi dihapus, defaultnya adalah ‘set null’ namun bisa kita atur
menjadi ‘restrict’ (mencegah dihapus) atau ‘cascade’ (ikut dihapus)
• Context dan domain, ini adalah default values yang akan digunakan
pada view di sisi client (client-side)
• One-to-Many Field adalah kebalikan dari Many-to-One, Namun tidak
Models: punya representasi data di dalam database. Sehingga One-to-Many
membutuhkan Field Many-to-One sebagai referensi
Relational Field • Many-to-many tidak menambahkan kolom di tabel, namun otomatis
membuat tabel baru sebagai intermediate relation dari kedua tabel,
dimana berisi 2 kolom yang terdiri dari 2 ID dari tabel tersebut.
Attribute dari Field One2many :
• comodel_name : Adalah target model dan bersifat mandatory untuk
semua field relational (o2m, m2o, m2m)
• inverse_name : Hanya berlaku di One2Many dan merupakan field di
tabel lawan yang harus berupa field many2one
• limit : Berlaku di One2many dan Many2one yang berisi batasan jumlah
record yang dipakai di level UI
• Disebut juga Nested Set Model, query dengan operator child_of akan
mempercepat proses.
class BookCategory(models.Model):
_name = 'library.book.category’
name = fields.Char('Category’)
parent_id = fields.Many2one('library.book.category’,
_parent_store = True
_parent_name = “parent_id”
parent_path = fields.Char(index=True)
Tambahkan kode berikut untuk mencegah looping/rekursif
class LibraryBook(models.Model):
# ...
_sql_constraints = [('name_uniq', 'UNIQUE (name)’,
'Book title must be unique.'),('positive_page’,
'CHECK(pages>0)’, 'No of pages must be positive’)]
• Check pada level server
Models: • Menggunakan @api.constraints(..)
Computed Fields
delta = today - book.date_release
book.age_days = delta.days
else:
book.age_days = 0
def _inverse_age(self):
today = fields.Date.today()
for book in self.filtered('date_release’):
d = today - timedelta(days=book.age_days)
book.date_release = d
# lanjutan dari class LibraryBook
def _search_age(self, operator, value):
today = fields.Date.today()
value_days = timedelta(days=value)
value_date = today - value_days
# convert the operator:
# book with age > value have a date < value_date
operator_map = {
'>': '<', '>=': '<=‘,
'<': '>', '<=': '>=‘,
}
new_op = operator_map.get(operator, operator)
return [('date_release', new_op, value_date)]
Models: • Computed Field mirip field biasa, bedanya ada attibute compute yang
berisi nama method komputasinya
Computed Fields • Computed Field secara dinamis dihitung nilainya saat runtime,
sehingga tidak disimpan di database. Sehingga secara default tidak
bisa dilakukan search atau write.
• ORM menggunakan teknik caching untuk mempercepat proses
kalkulasi dan bergantung pada field tertentu. Menggunakan decorator
@api.depends untuk rekalkulasi
• Pastikan method compute nya memberikan return value pada
computed field, jika tidak akan muncul Error
• Fungsi write dilakukan melalui method inverse, sehingga value di
computed field akan meng-update field asal
• Attribute inverse bersifat optional tidak perlu ada jika tidak ada
kebutuhan edit computed field
• Attribute search diisi jika ingin computed field dapat dilakukan
search
• Attibute store = True akan menyimpan field di database, sehingga
tidak dilakukan komputasi ulang secara runtime. Jika store = True,
maka tidak perlu lagi implementasi search method karena sudah
seperti field biasa.
• Attribute compute_sudo=True digunakan jika kasus komputasi
Models: membutuhkan level pengguna yang khusus.
• Odoo 12 (dan di bawahnya) secara default compute_sudo=False,
class LibraryBook(models.Model):
# ...
publisher_id = fields.Many2one('res.partner’,
Models: string='Publisher’)
model lain • Kita bisa akses city melalui publisher_id, atau bisa juga :
publisher_id.country_id.country_code
• Attribute readonly=True agar data tidak bisa diubah, Jika tidak
dilakukan maka data yang ter-relasi bisa ikut diubah
• Pada dasarnya related field adalah computed field namun
menggunakan cara yang lebih mudah
• Jika menggunakan relational field, perlu ditentukan target model /
comodel relasinya
• Kadang kita perlu mengijinkan user menentukan model yang dipilih
dan record yang dipilih juga, menggunakan reference field
menggunakan
reference fields
Models:
Inheritance
Ada 3 macam inheritance:
• Class inheritance (extension)
• Prototype inheritance
• Delegation inheritance
• Class inheritance bisa menambah modifikasi field atau method
pada model yang sudah ada.
• Pada database layer, ORM akan menambahkan/ mengubah field
pada tabel yang sama
• Fields akan dimodifikasi secara inkremental, artinya jika field sudah
ada (pada superclass), hanya atribut yang berbeda (pada inherited
class) maka hanya atribut tersebut yang dimodifikasi, selain itu akan
tetap sama seperti parent class
• Method yang didefinisikan di inherited class akan menggantikan
method di parent class. Jika kita tidak melakukan invoke /
memanggil method parent menggunakan super maka method parent
tidak akan dilakukan eksekusi
class LibraryMember(models.Model):
_name = 'library.member’
partner_id = fields.Many2one('res.partner’,
ondelete='cascade', delegate=True)
class BaseArchive(models.AbstractModel):
_name = 'base.archive’
active = fields.Boolean(default=True)
def do_archive(self):
for record in self:
class LibraryBook(models.Model):
_name = 'library.book’
_inherit = ['base.archive’]
# ... dst
“
Selanjutnya :
Basic Server-Side Development
”