12

Voglio creare una pagina con un elenco di utenti e caselle di controllo che segnalano se un utente è selezionato, che applicherà alcune azioni agli utenti selezionati. Ho creato una classe forma che assomiglia a questo:Come rendere il campo modulo django nel modello

#in forms.py 
class UserSelectionForm(forms.Form): 
    """form for selecting users""" 
    def __init__(self, userlist, *args, **kwargs): 
     self.custom_fields = userlist 
     super(forms.Form, self).__init__(*args, **kwargs) 
     for f in userlist: 
      self.fields[str(f.id)] = forms.BooleanField(initial=False)  

    def get_selected(self): 
     """returns selected users""" 
     return filter(lambda u: self.fields[str(u.id)], self.custom_fields) 

Nel mio modello ho utenti elencati in una tabella e voglio l'ultima colonna della tabella ad essere quelle caselle di controllo. Devo rendere i campi uno per uno a seconda del loro nome. Ho cercato di creare un tag modello che sarebbe tornato il codice html dell'elemento forma necessaria:

#in templatetags/user_list_tags.py 
from django import template 
register = template.Library() 

#this is django template tag for user selection form 
@register.filter 
def user_select_field(form, userid): 
    """ 
    returns UserSelectionForm field for a user with userid 
    """ 
    key = std(userid) 
    if key not in form.fields.keys(): 
     print 'Key %s not found in dict' % key 
     return None 
     return form.fields[key].widget.render(form, key) 

Infine, ecco il codice del modello:

<form action="" method="post"> 
{% csrf_token %} 
<table class="listtable"> 
    <tr> 
    <th>Username</th> 
    <th>Select</th> 
    </tr> 
{% for u in userlist %} 
    <tr> 
    <td>{{u.username}}</td> 
    <td>{{select_form|user_select_field:u.id}}</td> 
    </tr> 
{% endfor %} 
</table> 
<p><input type="submit" value="make actions" /></p> 

Tuttavia, questo non significa leghi questi widget alla forma e quindi, dopo aver inviato il modulo, la convalida fallisce. Il messaggio di errore dice che sono richiesti tutti i campi personalizzati. Così qui sono le mie domande:

  1. Qual è il modo giusto per rendere i campi del modulo separate?

  2. Qual è il modo corretto di creare un modulo con le caselle di controllo? (Voglio dire, forse il mio metodo è stupido e c'è un modo molto più semplice di ottenere ciò che voglio.

+0

forse dovresti provare a farlo con un piccolo javascript. – unni

+0

Non volevo usare javascript nel mio progetto su questo palco. Tuttavia, cosa dovrei fare esattamente? O cosa dovrei google? Sai che non sono un enorme javascript pro =) –

risposta

8

Ok Quindi penso Ho trovato un modo per rendere correttamente i campi dei moduli separati. L'ho trovato guardando le fonti di Django. La classe Django.forms.forms.BaseForm ha il metodo _html_output che crea un'istanza di Django.forms.forms.BoundField e quindi aggiunge unicode(boundField) all'output html. Ho fatto la stessa cosa e ha funzionato perfettamente:

#in templatetags/user_list_tags.py 
from django import template 
from django import forms 
register = template.Library() 

#this is djangp template tag for user selection form 
@register.filter 
def user_select_field(form, userid): 
    """ 
    returns UserSelectionForm field for a user with userid 
    """ 
    key = str(userid) 
    if key not in form.fields.keys(): 
     print 'Key %s not found in dict' % key 
     return None 
    #here i use BoundField: 
    boundField = forms.forms.BoundField(form, form.fields[key], key) 
    return unicode(boundField) 

che ha generato lo stesso HTML come {{}} form.as_p, quindi la richiesta POST sarà esattamente lo stesso e modulo saranno trattati in modo corretto.

ho anche corretto alcuni errori nella mia classe forma:

#in UserSelectionForm definition: 
... 
#__init__ 
for f in userlist: 
    self.fields[str(f.id)] = forms.BooleanField(initial=False, required=False) 
#get_selected  
return filter(lambda u: self.cleaned_data[str(u.id)], 
    self.custom_fields) 

che ora sembra lavorare come ho programmato, senza alcun javascript.

+3

Leggendo il [codice sorgente] (https://github.com/django/django/blob/master/django/forms/forms.py#L108) ho scoperto che invece di usare BoundField, è più pulito fare 'form [tasto ] 'e ottieni lo stesso BoundField. –

12

Stai facendo il modello di gran lunga troppo complicato. Aggiungere un'etichetta per ogni campo quando si crea nel __init__ il metodo di modulo.

for f in userlist: 
    self.fields[str(f.id)] = forms.BooleanField(label=f.username, initial=False) 

Poi, proprio ciclo sopra i campi del modulo e non preoccuparti più il userlist.

+0

Sfortunatamente, non posso farlo. Ho semplificato il mio codice un po 'per chiarire l'esempio. Nella mia versione della tabella, la riga con questa casella di controllo ha più di due colonne e vi è un altro widget oltre alle caselle di controllo ("metodo di selezione", in cui posso scegliere il meteo per selezionare tutti gli utenti o selezionato solo dalle caselle di controllo). Forse dovrei provare a dividere tutti quelli in forme separate?Perderà l'incapsulamento dei moduli 'metodo get_selected' ma potrebbe semplicemente eseguire l'operazione. –

Problemi correlati