Was ist neben der Syntax der Unterschied zwischen der Verwendung eines abstrakten Django-Modells und der Verwendung einer einfachen Python-Vererbung mit Django-Modellen? Vor-und Nachteile?
UPDATE: Ich glaube, meine Frage wurde missverstanden und ich erhielt Antworten auf den Unterschied zwischen einem abstrakten Modell und einer Klasse, die von django.db.models.Model erbt. Ich möchte den Unterschied zwischen einer Modellklasse, die von einer abstrakten Django-Klasse (Meta: abstract = True) erbt, und einer einfachen Python-Klasse, die beispielsweise von 'object' (und nicht models.Model) erbt, kennen.
Hier ist ein Beispiel:
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(...
Antworten:
Django generiert nur Tabellen für Unterklassen von
models.Model
, so dass die ersteren ...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)
... bewirkt, dass eine einzelne Tabelle nach dem Vorbild von ...
CREATE TABLE myapp_employee ( id INT NOT NULL AUTO_INCREMENT, first_name VARCHAR(255) NOT NULL, title VARCHAR(255) NOT NULL, PRIMARY KEY (id) );
... während letztere ...
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)
... werden keine Tabellen generiert.
Sie könnten Mehrfachvererbung verwenden, um so etwas zu tun ...
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)
... was eine Tabelle erstellen würde, aber die in der
User
Klasse definierten Felder ignoriert , sodass Sie eine Tabelle wie diese erhalten ...CREATE TABLE myapp_employee ( id INT NOT NULL AUTO_INCREMENT, title VARCHAR(255) NOT NULL, PRIMARY KEY (id) );
quelle
models.Model
, sodass in der Oberklasse definierte Felder nicht erfasst werden (es sei denn, sie sind auch Unterklassen vonmodels.Model
).ModelBase
's__new__
Aufruf führt es eine erste Überprüfung der Attribute der Klasse durch und prüft, ob der Attributwert eincontribute_to_class
Attribut hat - dasFields
, was Sie in Django definieren, tun dies alle sind in einem speziellen Wörterbuch enthalten,contributable_attrs
das letztendlich während der Migration weitergegeben wird, um die DDL zu generieren.Ein abstraktes Modell erstellt eine Tabelle mit dem gesamten Satz von Spalten für jedes Unterkind, während die Verwendung der "einfachen" Python-Vererbung einen Satz verknüpfter Tabellen erstellt (auch als "Mehrtabellenvererbung" bezeichnet). Betrachten Sie den Fall, in dem Sie zwei Modelle haben:
class Vehicle(models.Model): num_wheels = models.PositiveIntegerField() class Car(Vehicle): make = models.CharField(…) year = models.PositiveIntegerField()
Wenn
Vehicle
es sich um ein abstraktes Modell handelt, haben Sie eine einzige Tabelle:Wenn Sie jedoch eine einfache Python-Vererbung verwenden, haben Sie zwei Tabellen:
Wo
vehicle_id
ist ein Link zu einer Reihe inapp_vehicle
der auch die Anzahl der Räder für das Auto hätte.Jetzt wird Django dies gut in Objektform zusammenstellen, so dass Sie
num_wheels
als Attribut darauf zugreifen könnenCar
, aber die zugrunde liegende Darstellung in der Datenbank wird anders sein.Aktualisieren
Um Ihre aktualisierte Frage zu beantworten, besteht der Unterschied zwischen dem Erben von einer abstrakten Django-Klasse und dem Erben von Pythons
object
darin, dass das erstere als Datenbankobjekt behandelt wird (also werden Tabellen dafür mit der Datenbank synchronisiert) und das Verhalten von a hatModel
. Das Erben von einem einfachen Pythonobject
verleiht der Klasse (und ihren Unterklassen) keine dieser Eigenschaften.quelle
models.OneToOneField(Vehicle)
wäre auch gleichbedeutend mit dem Erben einer Modellklasse, oder? Und das würde zu zwei getrennten Tabellen führen, nicht wahr?num_wheels
ein Attribut für acar
, während Sie bei aOneToOneField
diese Dereferenzierung selbst durchführen müssen.app_car
Tabelle neu generiert werden, sodass sie auch dasnum_wheels
Feld enthält, anstatt denvehicle_id
Zeiger zu haben?Der Hauptunterschied besteht darin, wie die Datenbanktabellen für die Modelle erstellt werden. Wenn Sie die Vererbung ohne
abstract = True
Django verwenden, wird sowohl für das übergeordnete als auch für das untergeordnete Modell eine separate Tabelle erstellt, die die in jedem Modell definierten Felder enthält.Wenn Sie
abstract = True
für die Basisklasse verwenden, erstellt Django nur eine Tabelle für die Klassen, die von der Basisklasse erben - unabhängig davon, ob die Felder in der Basisklasse oder der ererbenden Klasse definiert sind.Vor- und Nachteile hängen von der Architektur Ihrer Anwendung ab. Anhand der folgenden Beispielmodelle:
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(...)
Wenn die
Publishable
Klasse nicht abstrakt ist Django wird eine Tabelle für publishables mit den Spalten erstellentitle
unddate
und getrennte Tabellen fürBlogEntry
undImage
. Der Vorteil dieser Lösung besteht darin, dass Sie in allen Publishables nach Feldern fragen können, die im Basismodell definiert sind, unabhängig davon, ob es sich um Blogeinträge oder Bilder handelt. Daher muss Django Verknüpfungen durchführen, wenn Sie z. B. Abfragen für Bilder durchführen ... Wenn SiePublishable
abstract = True
Django erstellen, wird keine TabellePublishable
für Blogeinträge und Bilder erstellt, die alle Felder (auch die geerbten) enthalten. Dies wäre praktisch, da für eine Operation wie get keine Verknüpfungen erforderlich wären.Siehe auch Djangos Dokumentation zur Modellvererbung .
quelle
Ich wollte nur etwas hinzufügen, was ich in anderen Antworten nicht gesehen habe.
Anders als bei Python-Klassen ist das Ausblenden von Feldnamen bei der Modellvererbung nicht zulässig .
Zum Beispiel habe ich Probleme mit einem Anwendungsfall wie folgt experimentiert:
Ich hatte ein Modell, das von Djangos auth PermissionMixin geerbt wurde :
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 # ...
Dann hatte ich mein Mixin, das unter anderem
related_name
dasgroups
Feld außer Kraft setzen sollte . So war es mehr oder weniger so: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.'))
Ich habe diese 2 Mixins wie folgt verwendet:
class Member(PermissionMixin, WithManagedGroupMixin): pass
Also ja, ich habe erwartet, dass das funktioniert, aber es hat nicht funktioniert. Das Problem war jedoch schwerwiegender, da der Fehler, den ich erhielt, überhaupt nicht auf die Modelle hinwies und ich keine Ahnung hatte, was schief lief.
Während ich versuchte, dies zu lösen, entschied ich mich zufällig, mein Mixin zu ändern und es in ein abstraktes Modell-Mixin umzuwandeln. Der Fehler hat sich folgendermaßen geändert:
django.core.exceptions.FieldError: Local field 'groups' in class 'Member' clashes with field of similar name from base class 'PermissionMixin'
Wie Sie sehen können, erklärt dieser Fehler, was los ist.
Das war meiner Meinung nach ein großer Unterschied :)
quelle
Der Hauptunterschied besteht darin, wann Sie die Benutzerklasse erben. Eine Version verhält sich wie eine einfache Klasse und die andere wie ein Django-Modus.
Wenn Sie die Basisversion "Objekt" erben, ist Ihre Employee-Klasse nur eine Standardklasse, und Vorname wird nicht Teil einer Datenbanktabelle. Sie können damit kein Formular erstellen oder andere Django-Funktionen verwenden.
Wenn Sie die models.Model-Version erben, verfügt Ihre Employee-Klasse über alle Methoden eines Django- Modells und erbt das Feld first_name als Datenbankfeld, das in einem Formular verwendet werden kann.
Laut der Dokumentation bietet ein abstraktes Modell "eine Möglichkeit, allgemeine Informationen auf Python-Ebene herauszufiltern und gleichzeitig nur eine Datenbanktabelle pro untergeordnetem Modell auf Datenbankebene zu erstellen".
quelle