Django-Manager Verkettung
Ich Frage mich, ob es möglich war (und wenn ja, wie) miteinander zu verketten mehrere Manager zum erzeugen einer Abfrage, die betroffen ist, indem sowohl der einzelnen Manager. Ich erkläre das konkrete Beispiel, an dem ich arbeite:
Habe ich mehrere abstrakte Modell-Klassen, die ich verwenden, um kleine, spezifische Funktionen zu anderen Modellen. Zwei dieser Modelle sind die DeleteMixin und ein GlobalMixin.
Den DeleteMixin so definiert:
class DeleteMixin(models.Model):
deleted = models.BooleanField(default=False)
objects = DeleteManager()
class Meta:
abstract = True
def delete(self):
self.deleted = True
self.save()
Im Grunde stellt es eine pseudo-löschen (deleted-flag), anstatt wirklich löschen des Objekts.
Den GlobalMixin so definiert:
class GlobalMixin(models.Model):
is_global = models.BooleanField(default=True)
objects = GlobalManager()
class Meta:
abstract = True
Es erlaubt jedes Objekt definiert werden, entweder als ein globales Objekt, oder ein eigenes Objekt (z.B. ein public/private-blog-post).
Beide haben Ihre eigenen Vorgesetzten, die Auswirkungen auf das queryset zurückgegeben wird. Meine DeleteManager Filter den queryset, um nur Ergebnisse zurück, die haben das gelöscht-flag auf False gesetzt, während die GlobalManager-Filter das queryset, um nur Ergebnisse zurück, die gekennzeichnet sind als global. Hier ist die Erklärung für beides:
class DeleteManager(models.Manager):
def get_query_set(self):
return super(DeleteManager, self).get_query_set().filter(deleted=False)
class GlobalManager(models.Manager):
def globals(self):
return self.get_query_set().filter(is_global=1)
Die gewünschte Funktionalität wäre ein Modell verlängern sowohl der diese abstrakten Modelle und gewähren die Möglichkeit, nur die Ergebnisse, die sind beide nicht gelöscht und global. Ich lief einen test-Fall auf ein Modell mit 4 Instanzen: eine Globale und nicht gelöscht, man war global und gelöscht, war eine nicht-Globale und nicht-gelöscht, und einer nicht-globalen und gelöscht werden. Wenn ich versuche, zu bekommen Ergebnismengen als solche: SomeModel.Objekte.alle(), bekomme ich die Instanz 1 und 3 (die zwei nicht-gelöschten - toll!). Wenn ich versuche SomeModel.Objekte.globals(), bekomme ich eine Fehlermeldung, dass DeleteManager nicht ein globals (dies wird vorausgesetzt, mein Modell Deklaration ist wie folgt: SomeModel(DeleteMixin, GlobalMixin). Wenn ich die Bestellung stornieren, habe ich nicht den Fehler, es heißt aber nicht, filtern die gelöschten). Wenn ich GlobalMixin zu befestigen GlobalManager zu globals anstelle von Objekten (also den neuen Befehl wäre SomeModel.globals.globals()), bekomme ich die Instanzen 1 und 2 (die beiden globals), während meine beabsichtigten Ergebnis führen würde, werden nur get-Instanz 1 (die global, nicht gelöscht werden).
Ich war mir nicht sicher, ob jemand in eine situation ähnlich wie diese, und hatte kommen zu einem Ergebnis. Entweder ein Weg, um es Arbeit in meine aktuellen Gedanken oder ein re-Arbeit, liefert die Funktionalität, die ich mir nach dem würde sehr geschätzt werden. Ich weiß, dieser post hat ein wenig langatmig. Wenn mehr Erklärung notwendig ist, würde ich mich gerne zur Verfügung stellen.
Edit:
Habe ich geschrieben die schließliche Lösung, die ich verwendet, um dieses spezielle problem weiter unten. Es beruht auf den link zu Simon ' s custom QuerySetManager.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sehen dieses snippet auf Djangosnippets: http://djangosnippets.org/snippets/734/
Anstatt Ihre benutzerdefinierten Methoden in einem manager, Sie eine Unterklasse der queryset selbst. Es ist sehr einfach und funktioniert perfekt. Das einzige Problem, das ich habe, ist mit dem Modell der Vererbung, man muss immer definieren, die manager im Modell Unterklassen (nur: "Objekte = QuerySetManager()" in der Unterklasse), obwohl Sie Erben die queryset. Dies wird sinnvoll, wenn Sie mit QuerySetManager.
Hier ist die spezifische Lösung für mein problem mit dem custom QuerySetManager von Simon, dass Scott verknüpft.
Jede mixin in die Zukunft, will fügen Sie zusätzliche Funktionalität, um die Abfrage muss einfach zu erweitern BaseMixin (oder haben es irgendwo in seinen bietet). Jedes mal, wenn ich versuche zum filtern der Abfrage festgelegt, wickelte ich es in eine try-catch-im Fall, dass das Feld tatsächlich nicht vorhanden ist (dh, es nicht zu verlängern, dass mixin). Der Globale filter ist aufgerufen, die Verwendung von globals(), während der filter löschen wird automatisch aufgerufen (wenn etwas gelöscht wird, habe ich nie wollen, es zu zeigen). Mit diesem system können für die folgenden Arten von Befehlen:
Eine Sache zu beachten ist, dass der filter löschen wirkt sich nicht auf die admin-interfaces, weil die Standard-Manager ist zuerst deklariert (und somit Standard). Ich erinnere mich nicht, Wann Sie verändert die admin-nutzen-Modell._default_manager statt Modell.Objekte, aber jeder gelöschte Instanzen werden noch in den admin (in Fall müssen Sie un-löschen Sie).
Verbrachte ich eine Weile versucht zu kommen mit ein Weg, um bauen eine schöne Fabrik zu tun, aber ich habe viel Probleme damit.
Die besten, die ich vorschlagen kann, ist die Kette Ihre Vererbung. Es ist nicht sehr allgemein, so bin ich nicht sicher, wie nützlich es ist, aber alles, was Sie zu tun haben ist:
Wenn Sie etwas mehr Generika, die beste, die ich mit oben kommen kann ist, zu definieren, eine Basis
Mixin
undManager
herausragendeget_query_set()
(ich nehme an, Sie wollen nur dieses eine mal; Dinge ziemlich kompliziert, nicht?) und übergeben Sie dann eine Liste der Felder, die Sie wollen, Hinzugefügt überMixin
s.Es würde in etwa so Aussehen (nicht getestet, bei allen):
Ok, also das ist hässlich, aber was hat es dich? Im wesentlichen ist es die gleiche Lösung, aber viel mehr Dynamik, und ein wenig mehr TROCKEN, obwohl schwieriger zu Lesen.
Zunächst erstellen Sie Ihren manager dynamisch:
Erzeugt einen neuen manager, die eine Unterklasse von
DeleteManager
und hat eine Methode namensglobals
.Als Nächstes erstellen Sie Ihre mixin Modell:
Wie gesagt, es ist hässlich. Aber es bedeutet, dass Sie nicht haben, um neu zu definieren
globals()
. Wenn Sie einen anderen Typ von manager, umglobals()
, rufen Sie einfachcreate_manager
wieder mit einer anderen Basis. Und Sie können so viele neue Methoden, wie Sie möchten. Dasselbe für die manager, die Sie gerade halten Sie das hinzufügen neuer Funktionen zurück, andere querysets.So, ist das wirklich praktisch? Vielleicht auch nicht. Diese Antwort ist mehr eine übung in der (ab)mit Python die Flexibilität. Ich habe nicht versucht, mit dieser, obwohl ich einige der zugrunde liegenden Prinzipien der dynamisch erweitern von Klassen um die Dinge leichter zu erreichen.
Lassen Sie mich wissen, wenn etwas unklar ist und ich werde zu aktualisieren, die Antwort.
Anderen option, die eine überlegung Wert ist die PassThroughManager:
https://django-model-utils.readthedocs.org/en/latest/managers.html#passthroughmanager