[pyar] múltiples objetos en un form django

Emiliano Lopez emiliano.lopez en gmail.com
Dom Feb 26 18:37:32 ART 2017


2017-02-21 10:56 GMT-03:00 Emiliano Lopez <emiliano.lopez en gmail.com>:
> Hola lista, les vuelvo a pedir ayuda con algo de django.
>
> Estoy renegando para armar un formulario con múltiples objetos. Según
> leo en la documentación la forma de solucionarlo es con formsets. Pero
> lo mio es un poco mas complicado de lo que ahí se explica.
>
> Me explayo un poco.
>
> Un modelo "tipo de estudio" tiene determinados parámetros cargados por
> el usuario. Luego, para cargar los resultados de un determinado tipo
> de estudio elijo de un menú desplegable el parámetro y en otro campo
> cargo el valor.
>
> Hasta ahí todo bien pero es medio incómodo, por lo que quisiera tener
> un formulario con todos los parámetros y al lado el campo
> correspondiente para guardarlos de una única vez.
>
> Simplificando un poco, los modelos en cuestión serían algo así:
>
> class Parametro(models.Model):
>     """Parámetros de cada estudio"""
>     estudio = models.ForeignKey('hc.Estudio', related_name='parametros')
>     texto = models.TextField()
>
> class Valor(models.Model):
>     resultado = models.ForeignKey('hc.ResultadoEstudio')
>     parametro = models.ForeignKey('hc.Parametro')
>     texto = models.TextField(blank=True, null=True)
>
> Lo que busco es crear un formulario con múltiples valores, uno por
> cada parámetro.
>
> Bueno, espero haber sido claro, les agradezco de antemano si me pueden ayudar.
>
> Saludos

La verdad es que te explicaste bastante mal, apenas yo te pude
entender y no sin esforzarme.

La solución viene de la mano de los formsets, lo que tenés que hacer
en la vista es crear este formulario múltiple, para eso se debe
importar
esto en la vista: from django.forms.formsets import formset_factory

ese formset_factory le pasás el form que querés replicar y la cantidad
de veces, en mi caso usé len(queryset) porque luego necesito usarlo,
pero sino podrías usar queryset.count() que es más eficiente

def valor_nuevo(request, pk_resultado):
    (...)
    parametros = Parametro.objects.filter(estudio=pk_estudio)
    ValorFormSet = formset_factory(ValorForm, extra=len(parametros))
    formset = ValorFormSet()
    i = 0
    for f in formset:
                f.fields['parametro'] =
forms.ModelChoiceField(parametros, widget=forms.Select())
                f.fields['parametro'].initial = parametros[i]
                f.fields['texto'].label = str(parametros[i])
                i += 1
    (...)
    return render(request, 'template.html', {'formset':formset})

de esta manera vas a crear un select con un valor por defecto
(.initial) en cada form, seguro se puede hacer de un modo mas limpio,
pero esa manera encontré yo, luego en el template los pongo ocultos
(hidden) y django mágicamente los convierte en inputs, en el template
hice algo así (conviene en una tabla, acá va mas limpio):

<form method="POST" role="form">{% csrf_token %}
      {{ formset.management_form}}
      {% for form in formset %}
              {{ form.parametro.as_hidden }}
              {{ form.texto.label_tag }}
              {{ form.texto }}
      {% endfor %}
      <button type="submit" class="btn btn-default">Guardar</button>
</form>

Con esto creás tu formulario con múltiples objetos vacios, es similar
en caso que sea un POST, pero esa no fue tu duda.
Espero que le sirva a alguien.
Saludos
emiliano


Más información sobre la lista de distribución pyar