12

Quiero hacer una página con una lista de usuarios y casillas de verificación que indiquen si un usuario está seleccionado, lo que aplicará alguna acción a los usuarios seleccionados. he creado una clase de formulario que se parece a esto:Cómo representar el campo de formulario django en la plantilla

#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) 

En mi plantilla tengo los usuarios listados en una mesa y quiero que la última columna de esta tabla sea aquellas casillas de verificación. Necesito representar campos uno por uno dependiendo de su nombre. He intentado crear una etiqueta de plantilla que devolvería el código HTML del elemento de forma necesaria:

#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) 

Por último, aquí está el código de la plantilla:

<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> 

Sin embargo, esto no se une esos widgets a la forma y, por lo tanto, después de enviar el formulario, la validación falla. El mensaje de error dice que todos los campos personalizados son obligatorios. Así que aquí están mis preguntas:

  1. ¿Cuál es la manera correcta de hacer que los campos del formulario por separado?

  2. ¿Cuál es la forma correcta de crear dicho formulario con casillas de verificación? (Quiero decir tal vez mi método es estúpida y no hay una manera mucho más fácil de lograr lo que quiero.

+0

tal vez deberías intentar hacer esto con un poco de javascript. – unni

+0

No quería usar javascript en mi proyecto en esta etapa. Sin embargo, ¿qué debería hacer exactamente? ¿O qué debería googlear? Sabes que no soy un gran javascript pro =) –

Respuesta

8

Ok Así que creo He encontrado una forma de representar correctamente campos de formulario separados. Lo encontré viendo fuentes django. Django.forms.forms.BaseForm clase tiene _html_output método que crea una instancia de Django.forms.forms.BoundField y luego agrega unicode(boundField) a la salida html. Hice exactamente lo mismo y funcionó perfectamente:

#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) 

que generó el mismo html como {{}} form.as_p, por lo que la solicitud POST se verá exactamente el mismo y la forma será procesada correctamente.

También me han solucionado algunos errores en mi clase de formulario:

#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) 

que ahora parece trabajar como había planeado, sin ningún tipo de Javascript.

+3

Leyendo el [código fuente] (https://github.com/django/django/blob/master/django/forms/forms.py#L108) Encontré que en lugar de usar BoundField, es más limpio hacer 'form [key ] 'y obtienes el mismo BoundField. –

12

Estás haciendo la plantilla demasiado complicado. Añadir una etiqueta para cada campo cuando se crea en el __init__ método de formulario.

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

A continuación, sólo un bucle sobre los campos del formulario y no se preocupe por la userlist más.

+0

Lamentablemente, no puedo hacer esto. Simplifiqué mi código un poco para clarificar el ejemplo. En mi versión, la fila de la tabla con esta casilla de verificación tiene más de dos columnas, y hay otro widget además de las casillas de verificación ("método de selección", donde puedo elegir el clima para seleccionar todos los usuarios o solo seleccionar mediante casillas de verificación). Tal vez debería intentar dividir todos esos en formas separadas?Perderá la incapsulación del método 'get_selected', pero puede simplemente hacer la tarea. –

Cuestiones relacionadas