Django Model Mixins: Von Models erben. Modell oder von Objekt?

78

Dies ist eine Frage zu Python-Mixins, die im Allgemeinen nützlich sein kann. Ich verwende nur Django-Modelle, da dies der Anwendungsfall ist, mit dem ich am besten vertraut bin.

Sollte ein Mixin von der Klasse erben, die mit oder von 'object' gemischt werden soll?

Beispiele nach Code, was ist korrekter oder besser oder besser, je nachdem, was Sie erreichen möchten?

Dies

class TaggingMixin(models.Model):
    tag = models.ForeignKey(Tag)

    class Meta:
        abstract = True

class MyModel(models.Model, TaggingMixin):
    title = models.CharField(max_length=100)

Oder dieses:

class TaggingMixin(object):
    tag = models.ForeignKey(Tag)

    class Meta:
        abstract = True

class MyModel(models.Model, TaggingMixin):
    title = models.CharField(max_length=100)

Ich denke, das Erben von Objekten ist der richtige Weg. Aber ich sehe Beispiele für den ersten Fall im ganzen Netz ...

EDIT: Ich habe meine Folgefrage auf eine separate Frage verschoben: Django Abstract Models gegen einfache Python-Mixins gegen Python ABCs

Hopla
quelle

Antworten:

82

Django macht eine Menge Metamagie, wenn es um seine Modellklassen geht. Leider funktioniert der übliche Ansatz für Mixins, wie er in Daniel Rosemans Antwort vorgeschlagen wurde - woher sie erben object- im Django-Universum nicht gut.

Der richtige Weg, um Ihre Mixins anhand des bereitgestellten Beispiels zu strukturieren, wäre:

class TaggingMixin(models.Model):
    tag = models.ForeignKey(Tag)

    class Meta:
        abstract = True

class MyModel(TaggingMixin):
    title = models.CharField(max_length=100)

Wichtige Punkte hier sind:

  • Mixins erben von model.Model, sind aber als abstrakte Klasse konfiguriert.
  • Da Mixins von erben model.Model, sollte Ihr tatsächliches Modell nicht davon erben. In diesem Fall wird möglicherweise eine Ausnahme für die Reihenfolge der konsistenten Methodenauflösung ausgelöst.
jsdalton
quelle
1
Dies führt zu TypeError: Cannot create a consistent method resolution order (MRO). Tun Sie class MyModel(TaggingMixin):stattdessen. Siehe stackoverflow.com/q/29214888/1627479
Joren
Danke @Joren. Die Antwort wurde bearbeitet, um dies widerzuspiegeln.
Jsdalton
21
"Mixin" ist hier ein falscher Begriff. Es ist nur ein abstraktes Modell. Sie können es nicht mit models.Modeloder anderen abstrakten Modellen "mischen"
David Avsajanishvili
15

Ich würde empfehlen, dass es von erbt object. Auf diese Weise können Sie sicherstellen, dass nur die Methoden und Attribute bereitgestellt werden, die Sie tatsächlich explizit definieren.

Außerdem sollten Sie immer sicherstellen, dass Sie die Mixin-Klasse an die erste Stelle setzen, wenn Sie Ihre konkrete Klasse definieren. Die Auflösungsregeln von Python bedeuten, dass die Oberklassen in der Reihenfolge ihrer Definition in der Klassendeklaration durchsucht werden und die Auflösung stoppt, wenn ein übereinstimmendes Attribut gefunden wird. Wenn Ihr Mixin eine Methode definiert, die auch von der Haupt-Superklasse definiert wird, wird Ihre Mixin-Methode nicht gefunden.

Daniel Roseman
quelle
12
Außer, dass die Metaklassenmagie, die Felder hinzufügt, nicht funktioniert, wenn Ihre Mixin-Klasse nicht erbt models.Model(oder genauer gesagt nicht über das __metaclass__erforderliche verfügt).
Matthew Schinckel
2
Das Erben von Objekten hat bei mir nicht funktioniert. Siehe: stackoverflow.com/questions/17343867/…
utapyngo
2
Objekt erben ist kein guter Weg für Django. weil Django-Auswanderungen es nicht erkennen können. Migrationsdateien enthalten nicht die abgelegten.
9nix00
Es wäre schön, ein kleines Beispiel mit einer Vorlage hinzuzufügen.
Pithikos
8

Dies sieht aus wie ein Job für ein abstraktes Modell .

BEARBEITEN:

Das sind keine Mixins an sich. Oder besser gesagt, sie müssen es nicht sein. Sie können direkt von einem abstrakten Modell ableiten.

Ignacio Vazquez-Abrams
quelle
1
Ähm, ja, Sie haben Recht, dies ist ein Job für ein abstraktes Modell. Tatsächlich habe ich sie nur im Code vergessen: s Ich habe es hinzugefügt, aber jetzt fange ich an, noch verwirrter über meine eigene Frage zu werden. .
Hopla
3

Wenn Sie von einem einfachen Python-Objekt erben, erstellt South keine Migration, sodass Sie diesen Ansatz nicht verwenden können

kharandziuk
quelle
1
Es hat nichts mit Südmigrationen zu tun.
Matthew Schinckel
Ich meine, dieser Ansatz spielt nicht gut mit South, was ein großes Problem für mich ist
kharandziuk