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 von models.Model) erbt, wissen.

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(...
76
rpq 20 Mai 2013 im 21:40

5 Antworten

Beste Antwort

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.

Django generiert nur Tabellen für Unterklassen von models.Model, also die erstere ...

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 Klasse User 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)
);
136
Aya 30 Mai 2013 im 14:19

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 ein abstraktes Modell ist, haben Sie eine einzige Tabelle:

app_car:
| id | num_wheels | make | year

Wenn Sie jedoch eine einfache Python-Vererbung verwenden, haben Sie zwei Tabellen:

app_vehicle:
| id | num_wheels

app_car:
| id | vehicle_id | make | model

Wobei vehicle_id eine Verknüpfung zu einer Zeile in app_vehicle ist, die auch die Anzahl der Räder für das Auto enthält.

Jetzt wird Django dies gut in Objektform zusammenstellen, so dass Sie auf num_wheels als Attribut auf Car zugreifen können, 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 (daher werden Tabellen dafür mit der Datenbank synchronisiert) und das Verhalten aufweist eines Model. Das Erben von einem einfachen Python object gibt der Klasse (und ihren Unterklassen) keine dieser Eigenschaften.

33
mipadi 31 Mai 2013 im 19:01

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 Modell und erbt das Feld Vorname als Datenbankfeld, das in einem Formular verwendet werden kann.

Laut Dokumentation ein abstraktes Modell "bietet eine Möglichkeit, allgemeine Informationen auf Python-Ebene herauszufiltern und gleichzeitig nur eine Datenbanktabelle pro untergeordnetem Modell auf Datenbankebene zu erstellen."

0
Brent Washburne 1 Juni 2013 im 00:43

Ich wollte nur etwas hinzufügen, was ich in anderen Antworten nicht gesehen habe.

Im Gegensatz zu Python-Klassen wird der Feldname Feldname ausgeblendet ist bei Modellvererbung nicht zulässig .

Zum Beispiel habe ich Probleme mit einem Anwendungsfall wie folgt experimentiert:

Ich hatte ein Modell, das von Djangos Authentifizierung 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 das related_name des groups Feldes überschreiben 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 :)

8
Adrián 2 Juni 2013 im 00:45

Der Hauptunterschied besteht darin, wie die Datenbanktabellen für die Modelle erstellt werden. Wenn Sie die Vererbung ohne abstract = True verwenden, erstellt Django eine separate Tabelle für das übergeordnete und das untergeordnete Modell, 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 Klasse Publishable nicht abstrakt ist, erstellt Django eine Tabelle für Veröffentlichungsdateien mit den Spalten title und date sowie separate Tabellen für BlogEntry und Image. Der Vorteil dieser Lösung besteht darin, dass Sie alle Veröffentlichungsdateien nach Feldern abfragen können, die im Basismodell definiert sind, unabhängig davon, ob es sich um Blogeinträge oder Bilder handelt. Aber deshalb muss Django Joins machen, wenn Sie z. Fragen Sie nach Bildern ... Wenn Sie Publishable abstract = True erstellen, erstellt Django keine Tabelle für Publishable, sondern nur für Blogeinträge und Bilder, 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.

11
davelupt 22 März 2016 im 13:05