Selain sintaks, apa perbedaan antara menggunakan model abstrak django dan menggunakan warisan Python biasa dengan model django? Pro dan kontra?
PEMBARUAN: Saya pikir pertanyaan saya disalahpahami dan saya menerima tanggapan atas perbedaan antara model abstrak dan kelas yang mewarisi dari django.db.models.Model. Saya sebenarnya ingin mengetahui perbedaan antara kelas model yang mewarisi dari kelas abstrak django (Meta: abstract = True) dan kelas Python biasa yang mewarisi dari katakanlah, 'object' (dan bukan models.Model).
Berikut ini contohnya:
class User(object):
first_name = models.CharField(..
def get_username(self):
return self.username
class User(models.Model):
first_name = models.CharField(...
def get_username(self):
return self.username
class Meta:
abstract = True
class Employee(User):
title = models.CharField(...
Jawaban:
Django hanya akan menghasilkan tabel untuk subkelas
models.Model
, jadi yang pertama ...class User(models.Model): first_name = models.CharField(max_length=255) def get_username(self): return self.username class Meta: abstract = True class Employee(User): title = models.CharField(max_length=255)
... akan menyebabkan satu tabel dibuat, di sepanjang baris ...
CREATE TABLE myapp_employee ( id INT NOT NULL AUTO_INCREMENT, first_name VARCHAR(255) NOT NULL, title VARCHAR(255) NOT NULL, PRIMARY KEY (id) );
... sedangkan yang terakhir ...
class User(object): first_name = models.CharField(max_length=255) def get_username(self): return self.username class Employee(User): title = models.CharField(max_length=255)
... tidak akan menyebabkan tabel apa pun dibuat.
Anda dapat menggunakan banyak warisan untuk melakukan sesuatu seperti ini ...
class User(object): first_name = models.CharField(max_length=255) def get_username(self): return self.username class Employee(User, models.Model): title = models.CharField(max_length=255)
... yang akan membuat tabel, tetapi akan mengabaikan bidang yang ditentukan di
User
kelas, jadi Anda akan mendapatkan tabel seperti ini ...CREATE TABLE myapp_employee ( id INT NOT NULL AUTO_INCREMENT, title VARCHAR(255) NOT NULL, PRIMARY KEY (id) );
sumber
models.Model
, jadi bidang yang ditentukan dalam superclass tidak akan diambil (kecuali mereka juga subkelas darimodels.Model
).ModelBase
's__new__
panggilan, ia melakukan pemeriksaan awal kelas' atribut, memeriksa apakah nilai atribut memilikicontribute_to_class
atribut - yangFields
yang Anda tetapkan di Django semua lakukan, sehingga mereka disertakan dalam kamus khusus yang disebutcontributable_attrs
yang pada akhirnya diteruskan selama migrasi untuk menghasilkan DDL.Model abstrak membuat tabel dengan seluruh kumpulan kolom untuk setiap sub-anak, sedangkan menggunakan pewarisan Python "biasa" membuat satu set tabel tertaut (alias "warisan multi-tabel"). Pertimbangkan kasus di mana Anda memiliki dua model:
class Vehicle(models.Model): num_wheels = models.PositiveIntegerField() class Car(Vehicle): make = models.CharField(…) year = models.PositiveIntegerField()
Jika
Vehicle
model abstrak, Anda akan memiliki satu tabel:app_car: | id | num_wheels | make | year
Namun, jika Anda menggunakan warisan Python biasa, Anda akan memiliki dua tabel:
app_vehicle: | id | num_wheels app_car: | id | vehicle_id | make | model
Di mana
vehicle_id
ada tautan ke barisapp_vehicle
yang juga memiliki jumlah roda untuk mobil tersebut.Sekarang, Django akan meletakkan ini bersama-sama dengan baik dalam bentuk objek sehingga Anda dapat mengakses
num_wheels
sebagai atribut padaCar
, tetapi representasi yang mendasari dalam database akan berbeda.Memperbarui
Untuk menjawab pertanyaan Anda yang diperbarui, perbedaan antara mewarisi dari kelas abstrak Django dan mewarisi dari Python
object
adalah yang pertama diperlakukan sebagai objek database (jadi tabel untuk itu disinkronkan ke database) dan memiliki perilaku aModel
. Mewarisi dari Python biasa tidakobject
memberikan kelas (dan subkelasnya) kualitas tersebut.sumber
models.OneToOneField(Vehicle)
juga akan setara dengan mewarisi kelas model, bukan? Dan itu akan menghasilkan dua tabel terpisah, bukan?num_wheels
atribut pada acar
, sedangkan dengan aOneToOneField
Anda harus melakukan dereferensi itu sendiri.app_car
tabel sehingga juga memilikinum_wheels
bidang, alih-alih memilikivehicle_id
penunjuk?Perbedaan utamanya adalah bagaimana tabel database untuk model dibuat. Jika Anda menggunakan pewarisan tanpa
abstract = True
Django akan membuat tabel terpisah untuk model induk dan anak yang menampung bidang yang ditentukan dalam setiap model.Jika Anda menggunakan
abstract = True
untuk kelas dasar Django hanya akan membuat tabel untuk kelas yang mewarisi dari kelas dasar - tidak peduli apakah bidang ditentukan dalam kelas dasar atau kelas yang mewarisi.Pro dan kontra bergantung pada arsitektur aplikasi Anda. Diberikan model contoh berikut:
class Publishable(models.Model): title = models.CharField(...) date = models.DateField(....) class Meta: # abstract = True class BlogEntry(Publishable): text = models.TextField() class Image(Publishable): image = models.ImageField(...)
Jika
Publishable
kelas bukan abstrak Django akan membuat tabel untuk terbitan dengan kolomtitle
dandate
dan tabel terpisah untukBlogEntry
danImage
. Keuntungan dari solusi ini adalah Anda dapat membuat kueri di semua yang dapat dipublikasikan untuk bidang yang ditentukan dalam model dasar, tidak peduli apakah itu entri blog atau gambar. Tetapi oleh karena itu Django harus melakukan penggabungan jika anda misalnya melakukan kueri untuk gambar ... Jika membuatPublishable
abstract = True
Django tidak akan membuat tabel untukPublishable
, tetapi hanya untuk entri blog dan gambar, berisi semua bidang (juga yang diwariskan). Ini akan berguna karena tidak ada gabungan yang diperlukan untuk operasi seperti get.Juga lihat dokumentasi Django tentang pewarisan model .
sumber
Hanya ingin menambahkan sesuatu yang belum pernah saya lihat di jawaban lain.
Berbeda dengan kelas python, penyembunyian nama bidang tidak diizinkan dengan pewarisan model.
Misalnya, saya telah bereksperimen dengan kasus penggunaan sebagai berikut:
Saya memiliki model yang diwarisi dari PermissionMixin auth django :
class PermissionsMixin(models.Model): """ A mixin class that adds the fields and methods necessary to support Django's Group and Permission model using the ModelBackend. """ is_superuser = models.BooleanField(_('superuser status'), default=False, help_text=_('Designates that this user has all permissions without ' 'explicitly assigning them.')) groups = models.ManyToManyField(Group, verbose_name=_('groups'), blank=True, help_text=_('The groups this user belongs to. A user will ' 'get all permissions granted to each of ' 'his/her group.')) user_permissions = models.ManyToManyField(Permission, verbose_name=_('user permissions'), blank=True, help_text='Specific permissions for this user.') class Meta: abstract = True # ...
Kemudian aku mixin saya yang antara lain Aku ingin menimpa
related_name
darigroups
lapangan. Jadi kurang lebih seperti ini:class WithManagedGroupMixin(object): groups = models.ManyToManyField(Group, verbose_name=_('groups'), related_name="%(app_label)s_%(class)s", blank=True, help_text=_('The groups this user belongs to. A user will ' 'get all permissions granted to each of ' 'his/her group.'))
Saya menggunakan 2 mixin ini sebagai berikut:
class Member(PermissionMixin, WithManagedGroupMixin): pass
Jadi ya, saya berharap ini berhasil tetapi ternyata tidak. Tetapi masalahnya lebih serius karena kesalahan yang saya dapatkan sama sekali tidak mengarah ke model, saya tidak tahu apa yang salah.
Ketika mencoba menyelesaikan ini, saya secara acak memutuskan untuk mengubah mixin saya dan mengubahnya menjadi mixin model abstrak. Kesalahan berubah menjadi ini:
django.core.exceptions.FieldError: Local field 'groups' in class 'Member' clashes with field of similar name from base class 'PermissionMixin'
Seperti yang Anda lihat, kesalahan ini menjelaskan apa yang sedang terjadi.
Ini adalah perbedaan yang sangat besar, menurut saya :)
sumber
Perbedaan utamanya adalah ketika Anda mewarisi kelas Pengguna. Satu versi akan berperilaku seperti kelas sederhana, dan yang lainnya akan berperilaku seperti model Django.
Jika Anda mewarisi versi "objek" dasar, kelas Karyawan Anda hanya akan menjadi kelas standar, dan first_name tidak akan menjadi bagian dari tabel database. Anda tidak dapat membuat formulir atau menggunakan fitur Django lainnya dengannya.
Jika Anda mewarisi versi models.Model, kelas Karyawan Anda akan memiliki semua metode Model Django , dan ini akan mewarisi bidang nama_pertama sebagai bidang basis data yang dapat digunakan dalam formulir.
Menurut dokumentasi, Model Abstrak "menyediakan cara untuk memfaktorkan informasi umum di tingkat Python, sementara masih hanya membuat satu tabel database per model anak di tingkat database."
sumber
Saya lebih suka kelas abstrak di sebagian besar kasus karena tidak membuat tabel terpisah dan ORM tidak perlu membuat gabungan dalam database. Dan menggunakan kelas abstrak cukup sederhana di Django
class Vehicle(models.Model): title = models.CharField(...) Name = models.CharField(....) class Meta: abstract = True class Car(Vehicle): color = models.CharField() class Bike(Vehicle): feul_average = models.IntegerField(...)
sumber