2010-10-14 5 views
6

eine Formularklasse Given (irgendwo tief in seinem riesigen Django app) ..Affe patching eine Django-Form-Klasse?

class ContactForm(forms.Form): 
    name = ... 
    surname = ... 

Und wenn man bedenkt Sie ein anderes Feld zu dieser Form ohne Erweiterung oder Veränderung der Form Klasse selbst hinzufügen möchten, tut, warum nicht die folgende ansatzarbeit?

ContactForm.another_field = forms.CharField(...) 

(Meine erste Vermutung ist, dass die Metaklasse hackery, die Django verwendet nur das erste Mal, gilt die Formularklasse aufgebaut. Wenn ja, wäre es eine Möglichkeit, um die Klasse zu deklarieren, dies zu überwinden?)

+0

Sie sind fast sicher richtig. Dies ist genau der Grund, warum Sie nicht einfach neue Felder zu einer Unterklasse models.Model hinzufügen können. –

+0

Bei Modellen gibt es das "syncdb" Problem, selbst wenn das Affepatching funktioniert. Aber mit Formen Affen Patching könnte ein Lebensretter zu bestimmten Zeiten IMHO sein. –

Antwort

7

Einige relevante Definitionen treten in django/forms/forms.py auf. Sie sind:

  1. class BaseForm
  2. class Form
  3. class DeclarativeFieldsMetaclass
  4. def get_declared_fields

get_declared_fields von DeclarativeFieldsMetaclass genannt wird und erstellt eine Liste mit den Feld Instanzen von ihrer Erstellung Zähler sortiert. Anschließend werden Felder aus den Basisklassen dieser Liste vorangestellt und das Ergebnis als Instanz zurückgegeben, wobei der Feldname als Schlüssel dient. DeclarativeFieldsMetaclass klebt dann diesen Wert in das Attribut base_fields und ruft type auf, um die Klasse zu konstruieren. Es übergibt dann die Klasse an die media_property-Funktion in widgets.py und verknüpft den Rückgabewert mit dem Attribut media für die neue Klasse.

media_property gibt eine Eigenschaftsmethode zurück, die die Medienerklärungen bei jedem Zugriff rekonstruiert. Mein Gefühl ist, dass es hier nicht relevant ist, aber ich könnte falsch liegen.

Auf jeden Fall, wenn Sie es nicht ein Media Attribut (und keinen der Basisklassen zu tun), dann nur deklarieren gibt eine frische Media Instanz ohne Argumente an den Konstruktor und ich denke, dass auf ein neues Feld monkeypatching sein sollte so einfach wie das Feld manuell in base_fields einfügen.

ContactForm.another_field = forms.CharField(...) 
ContactForm.base_fields['another_field'] = ContactForm.another_field 

Jede Formularinstanz erhält dann eine deepcopy von base_fields die form_instance.fields im __init__ Methode der BaseForm wird. HTH.

+0

Vielen Dank. Scheint, wie ein Charme zu arbeiten. –

+0

+1 Der Punkt OrderedDict führte mich zu SortedDict. Nicht sicher, was die Unterschiede sind, aber sie beide arbeiteten für mein Problem (weiß nicht über die OP's). Vielen Dank. – jrhorn424

Verwandte Themen