Saya ingin melakukan ini:
class Place(models.Model):
name = models.CharField(max_length=20)
rating = models.DecimalField()
class LongNamedRestaurant(Place): # Subclassing `Place`.
name = models.CharField(max_length=255) # Notice, I'm overriding `Place.name` to give it a longer length.
food_type = models.CharField(max_length=25)
Ini adalah versi yang ingin saya gunakan (meskipun saya terbuka untuk saran apa pun): http://docs.djangoproject.com/en/dev/topics/db/models/#id7
Apakah ini didukung di Django? Jika tidak, apakah ada cara untuk mencapai hasil yang serupa?
python
django
django-inheritance
Johnny 5
sumber
sumber
Jawaban:
Jawaban yang diperbarui: seperti yang dicatat orang dalam komentar, jawaban asli tidak menjawab pertanyaan dengan benar. Memang, hanya
LongNamedRestaurant
model yang dibuat dalam database,Place
tidak.Solusinya adalah membuat model abstrak yang mewakili "Tempat", misalnya.
AbstractPlace
, dan mewarisi darinya:Silakan baca juga jawaban @Mark , dia memberikan penjelasan yang bagus mengapa Anda tidak dapat mengubah atribut yang diwarisi dari kelas non-abstrak.
(Catatan ini hanya mungkin karena Django 1.10: sebelum Django 1.10, memodifikasi atribut yang diwarisi dari kelas abstrak tidak mungkin.)
sumber
Place
adalah abstrak, sehingga tidak dibuat di database. Tetapi OP menginginkan keduanyaPlace
danLongNamedRestaurant
dibuat dalam database. Oleh karena itu saya memperbarui jawaban saya untuk menambahkanAbstractPlace
model, yang merupakan model "dasar" (yaitu abstrak) baikPlace
danLongNamedRestaurant
diturunkan dari. Sekarang keduanyaPlace
danLongNamedRestaurant
dibuat dalam database, seperti yang diminta OP.Tidak, ini bukan :
sumber
User._meta.get_field('email').required = True
bisa bekerja, tidak yakin berpikir._meta
kelas induk, misalnyaMyParentClass._meta.get_field('email').blank = False
(untuk membuatemail
bidang yang diwariskan wajib di Admin)Itu tidak mungkin kecuali abstrak, dan inilah alasannya:
LongNamedRestaurant
juga aPlace
, tidak hanya sebagai kelas tetapi juga dalam database. Place-table berisi entri untuk setiap purePlace
dan untuk setiapLongNamedRestaurant
.LongNamedRestaurant
hanya membuat tabel tambahan denganfood_type
dan referensi ke tabel tempat.Jika Anda melakukannya
Place.objects.all()
, Anda juga mendapatkan setiap tempat yang aLongNamedRestaurant
, dan itu akan menjadi turunan dariPlace
(tanpafood_type
). JadiPlace.name
danLongNamedRestaurant.name
berbagi kolom database yang sama, dan karena itu harus berjenis sama.Saya pikir ini masuk akal untuk model normal: setiap restoran adalah sebuah tempat, dan setidaknya harus memiliki semua yang dimiliki tempat itu. Mungkin konsistensi ini juga mengapa tidak mungkin untuk model abstrak sebelum 1,10, meskipun tidak akan memberikan masalah database di sana. Seperti yang dikatakan @lampslave, hal itu dimungkinkan di 1.10. Saya pribadi merekomendasikan perawatan: jika Sub.x menimpa Super.x, pastikan Sub.x adalah subkelas dari Super.x, jika tidak Sub tidak dapat digunakan sebagai pengganti Super.x.
Solusi : Anda dapat membuat model pengguna khusus (
AUTH_USER_MODEL
) yang melibatkan cukup banyak duplikasi kode jika Anda hanya perlu mengubah bidang email. Sebagai alternatif, Anda dapat membiarkan email apa adanya dan memastikannya diwajibkan dalam segala bentuk. Ini tidak menjamin integritas database jika aplikasi lain menggunakannya, dan tidak berfungsi sebaliknya (jika Anda ingin membuat nama pengguna tidak diperlukan).sumber
Lihat https://stackoverflow.com/a/6379556/15690 :
sumber
Tempelkan kode Anda ke dalam aplikasi baru, tambahkan aplikasi ke INSTALLED_APPS dan jalankan syncdb:
Sepertinya Django tidak mendukung itu.
sumber
Bagian kode yang sangat keren ini memungkinkan Anda untuk 'mengganti' bidang di kelas induk abstrak.
Ketika field telah dihapus dari kelas induk abstrak, Anda bebas untuk mendefinisikan ulang sesuai kebutuhan.
Ini bukan pekerjaan saya sendiri. Kode asli dari sini: https://gist.github.com/specialunderwear/9d917ddacf3547b646ba
sumber
Mungkin Anda bisa berurusan dengan kontribusi_kelas_kelas:
Syncdb berfungsi dengan baik. Saya tidak mencoba contoh ini, dalam kasus saya, saya hanya mengganti parameter kendala jadi ... tunggu & lihat!
sumber
Place._meta.get_field('name').max_length = 255
di badan kelas harus melakukan trik, tanpa menimpa__init__()
. Akan lebih ringkas juga.Saya tahu ini pertanyaan lama, tetapi saya memiliki masalah serupa dan menemukan solusi:
Saya memiliki kelas-kelas berikut:
Tapi saya ingin bidang gambar warisan Tahun menjadi diperlukan sambil menjaga bidang gambar dari superclass nullable. Pada akhirnya saya menggunakan ModelForms untuk menegakkan gambar pada tahap validasi:
admin.py:
Tampaknya ini hanya berlaku untuk beberapa situasi (tentunya di mana Anda perlu menegakkan aturan yang lebih ketat di bidang subclass).
Alternatifnya, Anda dapat menggunakan
clean_<fieldname>()
metode ini sebagai ganticlean()
, misalnya jika suatu bidangtown
akan diminta untuk diisi:sumber
Anda tidak dapat mengganti bidang Model, tetapi mudah dicapai dengan mengganti / menetapkan metode clean (). Saya memiliki masalah dengan bidang email dan ingin membuatnya unik pada tingkat Model dan melakukannya seperti ini:
Pesan kesalahan tersebut kemudian ditangkap oleh kolom Formulir dengan nama "email"
sumber
Solusi saya sesederhana selanjutnya
monkey patching
, perhatikan bagaimana saya mengubahmax_length
atribut untukname
bidang dalamLongNamedRestaurant
model:sumber