Ich benutze Django erst seit ein paar Wochen, also könnte ich mich mit all diesen Unannehmlichkeiten beschäftigen, aber:
Ich habe eine Basis ModelForm, die ich einige BoilerPlate stuff, um die Dinge so trocken wie möglich zu halten, und alle meine tatsächlichen ModelForms Unterklasse nur diese Basisform. Das funktioniert gut für error_css_class = 'error'
und required_css_class = 'required'
, aber formfield_callback = add_css_classes
funktioniert nicht so, wie ich es erwarten würde.
Das Endziel besteht darin, einige jquery-Datetime-Picker auf Formularen mit einer Klasse von datefield / timefield / datetimefield zu schlagen. Ich möchte, dass alle Felder für Datumsangaben in der App dasselbe Widget verwenden. Daher entschied ich mich, dies so zu tun, anstatt es explizit für jedes Feld in jedem Modell zu tun. Das Hinzufügen einer zusätzlichen Zeile zu jeder Formularklasse ist nicht so ein großer Deal, aber es hat mich einfach gestört, dass ich es nicht herausfinden konnte. In der Django-Quelle herumzugrasen hat gezeigt, dass dies wahrscheinlich etwas tut, was ich nicht verstehe:
Aber ich weiß nicht, wie __init__
und __new__
alle miteinander verbunden sind. In BaseForm habe ich versucht, __init__
und formfield_callback vor und nach dem Aufruf von super zu überschreiben, aber ich vermute, dass es irgendwo in args oder kwargs sein muss.
__ new__ wird vor der Objektkonstruktion aufgerufen. Eigentlich ist dies eine factory Methode, die die Instanz eines neu konstruierten Objekts zurückgibt.
Also gibt es 3 Schlüsselzeilen in ModelFormMetaclass :
%Vor%In der Klasse fügen wir base_fields an unsere Form an.
Sehen wir uns jetzt die ModelForm-Klasse an:
%Vor%Dies bedeutet, dass ModelFormMetaclass .__ new __ (...) aufgerufen wird, wenn wir eine ModelForm-Instanz erstellen, um die Struktur der zukünftigen Instanz zu ändern. Und Attribute von __new__ ( def __new __ (cls, name, bases, attrs) ) in ModelFormMetaclass ist ein dict von allen Attributen von ModelForm-Klasse .
Die Entscheidung besteht also darin, eine neue InheritedFormMetaclass für unseren Fall zu erstellen (erbt diese von ModelFormMetaclass ). Vergessen Sie nicht, new des übergeordneten Elements in InheritedFormMetaclass aufzurufen. Erstellen Sie dann unsere BaseForm-Klasse und sagen Sie:
%Vor%In __new __ (...) Implementierung von InheritedFormMetaclass könnten wir alles tun, was wir wollen.
Wenn meine Antwort nicht detailliert genug ist, lassen Sie es mich bitte mit Hilfe von Kommentaren wissen.
Für das, was Sie erreichen möchten, ist es besser, wenn Sie einfach die Felder von form init durchlaufen. Zum Beispiel
%Vor%Natürlich brauchen Sie ein wenig mehr Logik für Ihren speziellen Fall. Wenn Sie den Ansatz verwenden möchten, den sergzach vorgeschlagen hat (Overkill für Ihr spezielles Problem, denke ich), hier ist ein Code für Sie, der formfield_callback für die Basisklasse aufruft, falls die Unterklasse ihn nicht definiert.
%Vor%Schließlich möchten Sie vielleicht in knusprige Formen schauen: Ссылка
sergzach ist richtig, dass Sie Metaklassen verwenden müssen; overriding __init__
ist nicht genug. Der Grund dafür ist, dass die Metaklasse für ModelForm (die für alle ModelForm-Unterklassen aufgerufen wird, sofern Sie keine andere Metaklasse in einer Unterklasse angeben) die Klassendefinition und die Verwendung der Werte in der Klassendefinition eine Klasse mit erstellt Klassenattribute Zum Beispiel werden sowohl META.fields als auch unser formfield_callback verwendet, um Formularfelder mit verschiedenen Optionen (wie dem Widget) zu erstellen.
Das bedeutet, dass AFAIU formfield_callback ein -Parameter für die Metaklasse ist, der beim Erstellen Ihrer benutzerdefinierten Modellformularklasse verwendet wird, nicht ein Wert, der zur Laufzeit beim Erstellen tatsächlicher Formularinstanzen verwendet wird. Das macht die Verwendung von formfield_callback in __init__
unbrauchbar.
Ich habe ein ähnliches Problem mit einer benutzerdefinierten Metaklasse wie
gelöst %Vor%und in der Basisklasse für alle meine Modellformen Einstellung der Metaklasse
%Vor%welches benutzt werden kann (zumindest in Django 1.6)
%Vor%Tags und Links django django-forms