2010-10-14 5 views
6

Data una classe form (da qualche parte nel profondo del vostro gigante Django app) ..Monkey patching una classe di forma Django?

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

E considerando che si desidera aggiungere un altro campo a questa forma, senza estendere o modificare la classe forma stessa, perché non la il seguente approccio funziona?

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

(La mia prima risposta è che la hackery metaclasse che Django utilizza applica solo la prima volta che la classe del form è costruito. Se è così, ci sarebbe un modo per ridichiarare classe per superare questo?)

+0

Hai quasi certamente ragione. Questo è esattamente il motivo per cui non è possibile aggiungere facilmente nuovi campi a modelli. Sottoclasse modello. –

+0

Con i modelli c'è il problema "syncdb" anche se la patch della scimmia ha funzionato. Ma con le forme di patch scimmia potrebbe essere un risparmiatore di vita in determinati momenti IMHO. –

risposta

7

Alcune definizioni pertinenti si verificano in django/forms/forms.py. Essi sono:

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

get_declared_fields è chiamato da DeclarativeFieldsMetaclass e costruisce un elenco con le istanze campo ordinato dal loro contatore creazione. Quindi inserisce i campi dalle classi base in questo elenco e restituisce il risultato come un'istanza OrderedDict con il nome del campo che funge da chiave. DeclarativeFieldsMetaclass quindi inserisce questo valore nell'attributo base_fields e chiama type per costruire la classe. Passa quindi la classe alla funzione media_property in widgets.py e allega il valore restituito all'attributo media nella nuova classe.

media_property restituisce un metodo di proprietà che ricostruisce le dichiarazioni dei supporti su ogni accesso. La mia sensazione è che non sarà rilevante qui, ma potrei sbagliarmi.

In ogni caso, se non si stiano dichiarando un attributo Media (e nessuna delle classi di base fare) allora restituisce solo una nuova Media un'istanza senza argomenti al costruttore e penso che monkeypatching un nuovo campo sulla dovrebbe essere Semplice come inserire manualmente il campo in base_fields.

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

esempio Ciascun modulo riceve poi una deepcopy di base_fields che diventa form_instance.fields nel metodo di BaseForm__init__. HTH.

+0

Grazie mille. Sembra funzionare come un fascino. –

+0

+1 Il punto su OrderedDict mi porta a SortedDict. Non sono sicuro di quali siano le differenze, ma entrambe hanno funzionato per il mio problema (non so degli OP). Grazie. – jrhorn424