2010-04-06 17 views
14

Vorrei creare un modulo che includa campi da due modelli separati, insieme ad altri campi regolari (non modello). Il modulo creerà un'istanza di ciascun modello. Io non so penso Posso usare i moduli in linea per questo, dato che non voglio includere tutti i campi di entrambi i modelli.Ottenere il campo modulo Django dal campo modello

Vorrei creare il campo modulo senza codificare il tipo dei campi del modello.

So che posso ottenere un campo modulo da un campo modello utilizzando model_field.formfield(). Ma come posso ottenere il campo del modello specifico?

La mia prima soluzione:

def get_fields(model_class): 
    fields = {} 
    for f in model_class._meta.fields: 
     fields[f.name] = f 

class MyForm(forms.Form): 
    foo_name = get_fields(Foo)['name'].formfield() 
    bar_name = get_fields(Bar)['name'].formfield() 
    other_field = ... 

Esiste un equivalente di get_fields già? È una cattiva idea? Mi sento a disagio nel fare affidamento sull'attributo modello _meta. O sto andando in questo modo completamente sbagliato?

+0

La soluzione sembra ragionevole per me, ma nemmeno, non vedo il motivo per cui non volete codificare quei 2 campi; forse ottieni i modelli dinamicamente. –

+0

Desidero evitare di codificare a macchina il tipo del campo modulo nel caso in cui cambi mai il tipo del campo modello corrispondente. Non sei sicuro di cosa intendessi per ottenere i modelli in modo dinamico ...? – harto

risposta

14

Puoi anche dare un'occhiata a django.forms.models.fields_for_model. Questo dovrebbe darti un dizionario di campi, e quindi puoi aggiungere i campi del modulo

+0

Non avevo notato quel metodo, grazie. Questa è la risposta che stavo cercando, ma forse il suggerimento di Casey Stark è più appropriato. – harto

11

Non dovresti mai costruire i campi da solo, a meno che tu non voglia un comportamento particolare.

Questo dovrebbe essere semplice come utilizzare due ModelForm s e un ulteriore Form all'interno di un tag <form> nel modello con un pulsante di invio.

in forms.py:

class Model1Form(forms.ModelForm): 
    class Meta: 
     model = Model1 
     fields = ('fields', 'you', 'want') 

class Model2Form(forms.ModelForm): 
    class Meta: 
     model = Model2 
     fields = ('fields', 'you', 'want') 

class ExtraFieldsForm(forms.Form): 
    extra_field = form.TextField() # or whatever field you're looking for 

in views.py:

form1 = Model1Form(request.POST or None) 
form2 = Model2Form(request.POST or None) 
form3 = ExtraFieldsForm(request.POST or None) 

if form1.is_valid() and form2.is_valid() and form3.is_valid(): 
    form1.save() 
    form2.save() 
    form3.save() 

    ...do other stuff like a redirect... 

e nel modello:

<form method="POST" action="">{% csrf_token %} 
    <fieldset> 
     {{ form1|as_uni_form }} 
     {{ form2|as_uni_form }} 
     {{ form3|as_uni_form }} 
     <div class="form_block"> 
      <input type="submit" value="Save both models"/> 
     </div> 
    </fieldset> 
</form> 

Sono abituato ad usare django-uni- forma, ma puoi rendere i campi del modulo come preferisci. Buona fortuna con il tuo sito.

+0

Non mi è venuto in mente di usare più oggetti 'Form' all'interno di un singolo elemento'

'. Grazie per il suggerimento - ci proverò stasera. – harto

+0

Fresco. Spero che funzioni per te. L'ho visto fare prima ma questo non è testato. Potrebbe essere necessario giocare con la logica della vista per ottenere quello che vuoi. –

2

Un'altra soluzione può essere quella di creare una forma "uber" che aggrega le forme di modello concrete. Il modulo supporta i metodi normalmente forniti da un modulo e li inoltra a tutte le forme figlio. Alcuni saranno semplici, altri complicati. Il grande vantaggio di questo approccio è che nessun codice al di fuori del modulo è interessato (codice di validazione del client e simili). Il concetto non è davvero rivoluzionario, ma immagino complicato da aggiungere in seguito. Paul

4

V'è ora una documented API per ottenere il campo Modello da una classe del modello:

my_model_field = MyModel._meta.get_field('my_model_field_name') 

Anche se non è ufficialmente documentato fino Django 1.8, questo dovrebbe funzionare con le versioni precedenti Django troppo.

Una volta fatto questo, è possibile ottenere il campo di modulo in questo modo:

form_field = my_model_field.formfield()