tag - formset django implementation
Pasando inicial en ModelFormSet de Django (10)
Creo que puedes usar el argumento inicial, como con los conjuntos de formularios regulares http://docs.djangoproject.com/en/dev/topics/forms/formsets/#using-initial-data-with-a-formset
Tengo un formset modelo al que necesito pasar la palabra clave inicial a (para tener algunos valores iniciales en el formset, como la fecha establecida hoy). Por lo que puedo decir, el argumento queryset (que por defecto es YourModel.objects.all ()) anula esta capacidad para la creación de formularios vacíos iniciales. Especifiqué el queryset como: YourModel.objects.none (), lo que impide que complete el formulario con las entradas de la base de datos, pero todavía no puedo averiguar cómo pasar el inicial de manera efectiva. ¿Necesito subclasificar un método de ModelForm?
Después de dos días encontré esto: http://streamhacker.com/2010/03/01/django-model-formsets/
def custom_field_callback(field):
return field.formfield(required=False)
FormSet = modelformset_factory(model, formfield_callback=custom_field_callback)
def custom_field_callback(field):
if field.name == ''optional'':
return field.formfield(required=False)
elif field.name == ''text'':
return field.formfield(widget=Textarea)
elif field.name == ''integer'':
return IntegerField()
else:
return field.formfield()
En Django 1.4, la regla cambió: el número de iniciales a mostrar corresponde al parámetro "extra". https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#providing-initial-values
En mi caso, el recuento de los parámetros iniciales varía dinámicamente, por lo que encontré la siguiente forma:
initial=[{''name'': ''Some Name''},{''name'': ''Another Name''}]
formset = ExampleModelFormSet(queryset=ExampleModel.objects.none(),
initial=initial, extra=len(initial))
class MyBaseFormSet(BaseModelFormSet):
def __init__(self, *args, **kwargs):
self.extra = kwargs.pop(''extra'', self.extra)
super(MyBaseFormSet, self).__init__(*args, **kwargs)
proporcionado, ExampleModelFormSet se basa en MyBaseFormSet
La forma sencilla de pasar datos iniciales con el mismo número de formularios adicionales:
MyModelFormSet = lambda *a, **kw: modelformset_factory(MyModel, extra=kw.pop(''extra'', 1))(*a, **kw)
Uso en vistas:
initial=[{''name'': ''Some Name''},{''name'': ''Another Name''}
formset = MyModelFormSet(queryset=MyModel.objects.none(), initial, extra=len(initial))})
La mejor manera que he encontrado para hacer esto es simplemente ajustar manualmente el atributo "extra" del objeto formset después de la inicialización. Esto ha sido probado y funciona en Django 1.9.
ExampleModelFormSet = modelformset_factory(ExampleModel, extra=1)
formset = ExampleModelFormSet(initial=[{''name'': ''Some Name''},
{''name'': ''Another Name''}])
formset.extra = 3
Esto escupirá 3 formularios (2 prepopulados y 1 en blanco).
Si quieres algo más dinámico (por ejemplo, initial
es una var calculada en otro lugar), puedes hacer algo como esto:
ExampleModelFormSet = modelformset_factory(ExampleModel, extra=1)
formset = ExampleModelFormSet(initial=initial)
formset.extra += len(initial)
Espero que ayude.
Nuevo en Django 1.4 ... si configura inicial en un conjunto de modelos, ahora solo se aplica a los formularios ''extra'', no a los enlazados a instancias desde el conjunto de consultas:
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#providing-initial-values
Por lo tanto, los diversos hacks anteriores ya no son necesarios y usar initial es la respuesta.
Puede alterar los datos iniciales después.
Por ejemplo:
# Construct the FormSet class
ExampleFormSet = modelformset_factory(ParentModel, ChildModel)
# Set the initial data
initial_data = {''field1'': 1}
for form in ExampleFormSet.extra_forms:
for field in form.fields:
field.initial = initial_data[field.name]
Todavía es posible pasar inicial a un ModelFormSet.
from django.forms.models import modelformset_factory
from example.models import ExampleModel
ExampleModelFormSet = modelformset_factory(ExampleModel)
formset = ExampleModelFormSet(initial=[{''name'': ''Some Name''},
{''name'': ''Another Name''}])
Si esto no es lo que buscas, ¿puedes explicar más tu pregunta?
EDITAR:
ExampleModelFormSet = modelformset_factory(ExampleModel, extra=2)
formset = ExampleModelFormSet(queryset=ExampleModel.objects.none(),
initial=[{''name'': ''Some Name''},
{''name'': ''Another Name''}])
Una solución simple podría ser que pase un formulario que extienda un modelform () a un formset (en lugar de modelformset).
De esa manera puede establecer valores iniciales en el formulario.
Usted está pasando un queryset vacío a ModelFormset.
ExampleModelFormSet = modelformset_factory(ExampleModel, extra=2)
formset = ExampleModelFormSet(queryset=ExampleModel.objects.none(),
initial=[{''name'': ''Some Name''},
{''name'': ''Another Name''}])
que es precisamente la manera de lograr lo que quieres. Tiene sentido pasar un conjunto de consultas vacío, de lo contrario los valores iniciales anularán el valor de la base de datos del modelo.
Y si supongo que está pasando un queryset no vacío, y aún así desea que sus formularios adicionales se llenen con valores iniciales, puede anular el Formset
.
from django.forms.models import modelformset_factory
ExampleFormset = modelformset_factory(OpenIDProfile, extra=3)
class myFormset(ExampleFormset):
def _construct_form(self, i, **kwargs):
"""
Instantiates and returns the i-th form instance in a formset.
"""
if self.is_bound and i < self.initial_form_count():
pk_key = "%s-%s" % (self.add_prefix(i), self.model._meta.pk.name)
pk = self.data[pk_key]
pk_field = self.model._meta.pk
pk = pk_field.get_db_prep_lookup(''exact'', pk)
if isinstance(pk, list):
pk = pk[0]
kwargs[''instance''] = self._existing_object(pk)
if i < self.initial_form_count() and not kwargs.get(''instance''):
kwargs[''instance''] = self.get_queryset()[i]
defaults = {''auto_id'': self.auto_id, ''prefix'': self.add_prefix(i)}
if self.data or self.files:
defaults[''data''] = self.data
defaults[''files''] = self.files
# Check to confirm we are not overwriting the database value.
if not i in range(self.initial_form_count()) and self.initial:
try:
defaults[''initial''] = self.initial[i - self.initial_form_count()]
except IndexError:
pass
# Allow extra forms to be empty.
if i >= self.initial_form_count():
defaults[''empty_permitted''] = True
defaults.update(kwargs)
form = self.form(**defaults)
self.add_fields(form, i)
return form
Nota: initial
es lista de dicts. Es deseable tener elementos en la lista exactamente igual al número de extra.