2016-09-26 2 views
1

Ich versuche, eine App, die ich erstellt habe, so zu ändern, dass sie wiederverwendbar ist. Es basiert auf einem einzelnen Modell, die Websites mit der App Unterklasse wird. Wie es steht, hat meine nicht wiederverwendbare Version die folgende Art von Struktur:So verwenden Sie Basisklassen in Django

# models.py 
class Document(models.Model): 
    contents = models.TextField() 
    date = models.DateTimeField() 

# views.py 
from .models import SiteModel 
# ... 
class MyView(ListView): 
    def some_method(self, list_of_pks): 
     model_vals = Document.objects.filter(pk__in = list_of_pks).values() 

def perform_action(request): 
    obj_pk = request.POST.get('obj_pk') 
    obj = Document.objects.filter(pk = obj_pk) 

    MySignal.send(sender=Document, instance = obj) 

#etc, etc 

Das funktioniert gut genug. Aber mein Anwendungsfall erfordert verschiedene Arten von Document, einen pro Standort, der zusätzliche Felder haben wird, die nicht im Voraus bekannt sind. Basierend auf dem Lesen die Dokumentation auf abstract base classes, dachte ich, die eine vernünftige Lösung aussehen würde:

# models.py for the app 
class BaseDocument(models.Model): 
    contents = models.TextField() 

    class Meta: 
     abstract = True 

# models.py for a hypothetical site using the app 
class SiteDocument(myapp.BaseDocument): 
    date = models.DateTimeField() 
    # other site-specific fields 

Was ich nicht verstehe ist, wie dann, um das Modell in den views.py App zu verweisen, forms.py usw. Ich weiß BaseDocument.objects.all() Zum Beispiel wird nichts zurückgegeben, da es nicht mit einer Datenbank verbunden ist. Umgekehrt kann ich Document.objects.all() nicht haben, weil Document noch nicht erstellt wurde und für jede Site spezifisch ist. Ist eine abstrakte Basisklasse nicht die richtige Lösung und wenn ja, was ist das?

Edit:

Es sieht aus wie ein OneToOneField mit meinem Anwendungsfall kann am besten geeignet, obwohl es so aussieht, dass Methoden aus der übergeordneten Klasse schließt vererben und dass BaseDocument.objects.all() nicht alle seine Kinder auflisten.

Alternativ fragte ich mich, ob ich meiner abstrakten Basisklasse im Stil von get_user_model() einfach eine -Methode hinzufügen könnte?

Antwort

0

Ich landete mit einer Lösung gehen erwähnt in mein Edit, nämlich das Erstellen einer Methode, inspiriert von get_user_model(). Dies gibt mir genau das gewünschte Verhalten.

# models.py in app1 
from django.db import models 
from django.apps import apps as django_apps 

class BaseDocument(models.Model): 
    contents = models.TextField() 

    class Meta: 
     abstract = True 

    def get_document_model(): 
     # exception handling removed for concision's sake 
     return django_apps.get_model(settings.DOCUMENT_MODEL) 

# models.py in app2 
from django.db import models 
from app1.models import BaseDocument 

class SiteDocument(BaseDocument): 
    date = models.DateTimeField() 

Während views.py und anderswo, änderte ich Dinge, die von der Form Document.objects.all() zu BaseDocument().get_document_model().objects.all() gewesen wäre.

0

Sie können Ihre abstrakten Klassen nicht direkt abfragen, da sie keine Manager haben, sondern nur die geerbten Klassen. Wenn Sie wirklich Vererbung durchführen müssen, können Sie ein konkretes Basismodell verwenden und davon auf Kosten einer Verknüpfung bei jeder Abfrage erben.

Denken Sie lange darüber nach, ob dies wirklich notwendig ist oder ob Sie Ihre Daten allgemeiner darstellen können. Modelle machen Vererbung einfach, aber sie sind keine Magie. Es gibt sehr reale Leistungs- und Komplexitätsbetrachtungen.

Es könnte so einfach sein wie das Hinzufügen eines type Feld zu Ihrem Modell

class Document(models.Model): 
    DOCUMENT_TYPES = ['site', 'another', 'whatever'] 

    document_type = models.CharField(choices=DOCUMENT_TYPES) 
    ... 

Weitere Informationen zu abstrakt vs konkrete Klassen und Abfrage-, besuchen How to query abstract-class-based objects in Django?

+0

Ich bin nicht besonders auf Vererbung oder eine abstrakte Basisklasse verpflichtet, ich hatte gerade den Eindruck, dass die passende Lösung war. Dies kann ein XY-Problem sein, und ich kann meinen Anwendungsfall nicht artikulieren. Die Websites, die die App verwenden, verwenden immer nur ein "Dokument", aber wir kennen ihre Felder nicht im Voraus. Ich denke, meine Frage könnte wie folgt umformuliert werden: Wie beziehe ich mich in meiner App auf das Modell, wohl wissend, dass jede gegebene Seite dieses Modell ableiten und erweitern wird? – HoHo

+0

Ich weiß, ich brauche 'BaseDocument' nicht, um konkret zu sein, so dass Join unnötig erscheint, könnte ich einen ForeignKey verwenden, um auf ein mögliches Kind zu verweisen, dann in' views' etwas tun wie 'BaseDocument.doc_child.objects.all() '? – HoHo

+0

Sind die Dokumente in einer tatsächlichen Hierarchie oder suchen Sie nur nach Möglichkeiten zur Pseudo-Vererbung? Wenn Sie es nicht wirklich rechtfertigen können, brauchen Sie wahrscheinlich keine Vererbung. – Soviut

Verwandte Themen