modal - vistas basadas en clases django 2
Vistas basadas en clase de django con forma de modelo en lĂnea o formset (7)
Acabo de agregar mi propia versión después de verificar algunos de los CBV prefabricados. Específicamente necesitaba control sobre multiple formsets -> one parent
en una sola vista, cada uno con funciones de guardado individuales.
Básicamente rellené el enlace de datos FormSet en una función get_named_formsets
que es llamada por get_context_data
y form_valid
.
Allí, compruebo si todos los conjuntos de formularios son válidos, y también busco un método que anule un viejo formset.save()
simple por conjunto de formset.save()
para el guardado personalizado.
La plantilla procesa formularios a través de
{% with named_formsets.my_specific_formset as formset %}
{{ formset }}
{{ formset.management_form }}
{% endwith %}
Creo que usaré este sistema regularmente.
class MyView(UpdateView): # FormView, CreateView, etc
def get_context_data(self, **kwargs):
ctx = super(MyView, self).get_context_data(**kwargs)
ctx[''named_formsets''] = self.get_named_formsets()
return ctx
def get_named_formsets(self):
return {
''followup'': FollowUpFormSet(self.request.POST or None, prefix=''followup''),
''action'': ActionFormSet(self.request.POST or None, prefix=''action''),
}
def form_valid(self, form):
named_formsets = self.get_named_formsets()
if not all((x.is_valid() for x in named_formsets.values())):
return self.render_to_response(self.get_context_data(form=form))
self.object = form.save()
# for every formset, attempt to find a specific formset save function
# otherwise, just save.
for name, formset in named_formsets.items():
formset_save_func = getattr(self, ''formset_{0}_valid''.format(name), None)
if formset_save_func is not None:
formset_save_func(formset)
else:
formset.save()
return http.HttpResponseRedirect('''')
def formset_followup_valid(self, formset):
"""
Hook for custom formset saving.. useful if you have multiple formsets
"""
followups = formset.save(commit=False) # self.save_formset(formset, contact)
for followup in followups:
followup.who = self.request.user
followup.contact = self.object
followup.save()
Tengo los siguientes modelos:
class Bill(models.Model):
date = models.DateTimeField(_("Date of bill"),null=True,blank=True)
class Item(models.Model):
name = models.CharField(_("Name"),max_length=100)
price = models.FloatField(_("Price"))
quantity = models.IntegerField(_("Quantity"))
bill = models.ForeignKey("Bill",verbose_name=_("Bill"),
related_name="billitem")
Sé que esto es posible:
from django.forms.models import inlineformset_factory
inlineformset_factory(Bill, Item)
y luego procesar esto a través de una vista estándar.
Ahora me preguntaba, si hay una forma de lograr lo mismo (es decir, usar un en línea para agregar / editar elementos que pertenecen a una factura) usando vistas basadas en clases (no para la interfaz de administración).
Deberías probar django-extra-views . Busque CreateWithInlinesView
y UpdateWithInlinesView
.
El código en la respuesta de Jordan no funcionó para mí. Publiqué mi propia pregunta sobre esto, que creo que ahora he resuelto. El primer argumento para inlineformset_factory debe ser Book, not BookForm.
Hice algunas modificaciones a la solución original para permitir que formset.is_valid () funcione:
if self.request.POST:
context[''fs''] = MyInlineFS(self.request.POST, instance=self.object)
else:
context[''fs''] = MyInlineFS(instance=self.object)
Los puntos clave son:
FormSet
generados dentro deforms.py
usandoinlineformset_factory
:BookImageFormSet = inlineformset_factory(BookForm, BookImage, extra=2) BookPageFormSet = inlineformset_factory(BookForm, BookPage, extra=5)
devolvió los
FormSet
s dentro de una claseviews.py
enviews.py
:def get_context_data(self, **kwargs): context = super(BookCreateView, self).get_context_data(**kwargs) if self.request.POST: context[''bookimage_form''] = BookImageFormSet(self.request.POST) context[''bookpage_form''] = BookPageFormSet(self.request.POST) else: context[''bookimage_form''] = BookImageFormSet() context[''bookpage_form''] = BookPageFormSet() return context
Se utilizó
form_valid
para guardar el formulario y formset:def form_valid(self, form): context = self.get_context_data() bookimage_form = context[''bookimage_formset''] bookpage_form = context[''bookpage_formset''] if bookimage_form.is_valid() and bookpage_form.is_valid(): self.object = form.save() bookimage_form.instance = self.object bookimage_form.save() bookpage_form.instance = self.object bookpage_form.save() return HttpResponseRedirect(''thanks/'') else: return self.render_to_response(self.get_context_data(form=form))
Necesitaba hacer una modificación más a get_context_data()
la vista de Jordan y Speq para tener formset.non_form_errors
en el contexto de la plantilla.
...
if self.request.POST:
context[''fs''] = MyInlineFS(self.request.POST, instance=self.object)
context[''fs''].full_clean() # <-- new
else:
context[''fs''] = MyInlineFS(instance=self.object)
return context
Redijo el código fuente genérico del 1.3-beta-1:
El código no está listo para la edición de listas o hay algo de magia negra aquí. Pero creo que se puede implementar rápidamente.
Si observa el módulo django.view.generic.edit (que admite edición de objetos detallados) cómo utiliza el módulo django.view.generic.detail.
Creo que se puede implementar un módulo django.view.generic.list_edit usando django.view.generic.list y alguna parte de django.view.generic.edit.