Ich möchte dies tun:
class Place(models.Model):
name = models.CharField(max_length=20)
rating = models.DecimalField()
class LongNamedRestaurant(Place): # Subclassing `Place`.
name = models.CharField(max_length=255) # Notice, I'm overriding `Place.name` to give it a longer length.
food_type = models.CharField(max_length=25)
Dies ist die Version, die ich verwenden möchte (obwohl ich für jeden Vorschlag offen bin): http://docs.djangoproject.com/de/dev/topics/db/models/#id7
Wird dies in Django unterstützt? Wenn nicht, gibt es eine Möglichkeit, ähnliche Ergebnisse zu erzielen?
python
django
django-inheritance
Johnny 5
quelle
quelle
Antworten:
Aktualisierte Antwort: Wie in den Kommentaren erwähnt, hat die ursprüngliche Antwort die Frage nicht richtig beantwortet. In der Tat wurde nur das
LongNamedRestaurant
Modell in der Datenbank erstellt,Place
nicht.Eine Lösung besteht darin, ein abstraktes Modell zu erstellen, das einen "Ort" darstellt, z.
AbstractPlace
und erben davon:Bitte lesen Sie auch @ Mark Antwort , er gibt eine gute Erklärung, warum Sie Attribute, die von einer nicht abstrakten Klasse geerbt wurden, nicht ändern können.
(Beachten Sie, dass dies nur seit Django 1.10 möglich ist: Vor Django 1.10 war das Ändern eines von einer abstrakten Klasse geerbten Attributs nicht möglich.)
quelle
Place
war abstrakt, daher wurde es nicht in der Datenbank erstellt. Aber OP wollte beidesPlace
undLongNamedRestaurant
in der Datenbank erstellt werden. Daher habe ich meine Antwort aktualisiert, um dasAbstractPlace
Modell hinzuzufügen , das sowohl das "Basismodell" (dh das abstrakte Modell) istPlace
und von demLongNamedRestaurant
erbt. Jetzt werden beidePlace
undLongNamedRestaurant
in der Datenbank erstellt, wie OP es verlangt.Nein, das ist es nicht :
quelle
User._meta.get_field('email').required = True
könnte funktionieren, nicht sicher gedacht._meta
der übergeordneten KlasseMyParentClass._meta.get_field('email').blank = False
email
Das ist nur möglich, wenn abstrakt, und hier ist der Grund:
LongNamedRestaurant
ist auch einePlace
, nicht nur als Klasse, sondern auch in der Datenbank. Die Platztabelle enthält einen Eintrag für jeden ReinenPlace
und für jedenLongNamedRestaurant
.LongNamedRestaurant
Erstellt einfach eine zusätzliche Tabelle mit demfood_type
und einem Verweis auf die Ortstabelle.Wenn Sie dies tun
Place.objects.all()
, erhalten Sie auch jeden Ort, der ein istLongNamedRestaurant
, und es wird eine Instanz vonPlace
(ohne dasfood_type
) sein. AlsoPlace.name
undLongNamedRestaurant.name
teilen Sie die gleiche Datenbankspalte und müssen daher vom gleichen Typ sein.Ich denke, das macht für normale Models Sinn: Jedes Restaurant ist ein Ort und sollte zumindest alles haben, was dieser Ort hat. Vielleicht ist diese Konsistenz auch der Grund, warum es für abstrakte Modelle vor 1.10 nicht möglich war, obwohl es dort keine Datenbankprobleme geben würde. Wie @lampslave bemerkt, wurde dies in 1.10 ermöglicht. Ich würde persönlich Vorsicht empfehlen: Wenn Sub.x Super.x überschreibt, stellen Sie sicher, dass Sub.x eine Unterklasse von Super.x ist, andernfalls kann Sub nicht anstelle von Super verwendet werden.
Problemumgehungen : Sie können ein benutzerdefiniertes Benutzermodell (
AUTH_USER_MODEL
) erstellen, das eine erhebliche Codeduplizierung erfordert, wenn Sie nur das E-Mail-Feld ändern müssen. Alternativ können Sie die E-Mail unverändert lassen und sicherstellen, dass sie in allen Formularen erforderlich ist. Dies garantiert keine Datenbankintegrität, wenn andere Anwendungen es verwenden, und funktioniert nicht umgekehrt (wenn Sie den Benutzernamen nicht benötigen möchten).quelle
Siehe https://stackoverflow.com/a/6379556/15690 :
quelle
Fügte Ihren Code in eine neue App ein, fügte eine App zu INSTALLED_APPS hinzu und führte syncdb aus:
Sieht so aus, als würde Django das nicht unterstützen.
quelle
Mit diesem supercoolen Code können Sie Felder in abstrakten übergeordneten Klassen überschreiben.
Wenn die Felder aus der abstrakten übergeordneten Klasse entfernt wurden, können Sie sie nach Bedarf neu definieren.
Dies ist nicht meine eigene Arbeit. Originalcode von hier: https://gist.github.com/specialunderwear/9d917ddacf3547b646ba
quelle
Vielleicht könnten Sie sich mit contrib_to_class befassen:
Syncdb funktioniert gut. Ich habe dieses Beispiel nicht ausprobiert. In meinem Fall habe ich nur einen Einschränkungsparameter überschrieben, also ... abwarten!
quelle
Place._meta.get_field('name').max_length = 255
in der Klasse sollte der Körper den Trick machen, ohne zu überschreiben__init__()
. Wäre auch prägnanter.Ich weiß, dass es eine alte Frage ist, aber ich hatte ein ähnliches Problem und fand eine Problemumgehung:
Ich hatte folgende Klassen:
Aber ich wollte, dass das geerbte Bildfeld von Year erforderlich ist, während das Bildfeld der Oberklasse nullbar bleibt. Am Ende habe ich ModelForms verwendet, um das Image in der Validierungsphase zu erzwingen:
admin.py:
Es scheint, dass dies nur für einige Situationen gilt (sicherlich, wenn Sie strengere Regeln für das Unterklassenfeld durchsetzen müssen).
Alternativ können Sie die
clean_<fieldname>()
Methode anstelle von verwendenclean()
, z. B. wenn ein Feldtown
ausgefüllt werden müsste:quelle
Sie können Modellfelder nicht überschreiben, dies kann jedoch leicht durch Überschreiben / Angeben der clean () -Methode erreicht werden. Ich hatte das Problem mit dem E-Mail-Feld und wollte es auf Modellebene einzigartig machen.
Die Fehlermeldung wird dann vom Formularfeld mit dem Namen "email" erfasst.
quelle
Meine Lösung ist so einfach wie die nächste
monkey patching
. Beachten Sie, wie ich dasmax_length
Attribut für dasname
Feld imLongNamedRestaurant
Modell geändert habe :quelle