Crear un modelo y modelos relacionados con conjuntos de formularios en línea

[He publicado esto en los usuarios de Django | Grupos de Google también.]

Utilizando el ejemplo en los documentos del conjunto de formularios en línea , puedo editar objetos que pertenecen a un modelo en particular (usando formas de modelo). He intentado seguir el mismo patrón para crear objetos nuevos utilizando formularios en línea, pero no he podido aclarar mi mente lo suficiente como para sacar una vista de trabajo para este propósito.

Usando el mismo ejemplo que en el enlace anterior, ¿cómo podría crear una nueva instancia de un modelo de “Autor” junto con sus objetos “Libro” relacionados?

Primero, crea un formulario modelo de autor.

author_form = AuthorModelForm() 

luego crea un objeto de autor ficticio:

 author = Author() 

A continuación, cree un formset en línea usando el autor ficticio de la siguiente manera:

 formset = BookFormSet(instance=author) #since author is empty, this formset will just be empty forms 

Envía eso a una plantilla. Después de que los datos vuelvan a la vista, usted crea el Autor:

 author = AuthorModelForm(request.POST) created_author = author.save() # in practice make sure it's valid first 

Ahora enganche el formset en línea con el autor recién creado y luego guárdelo:

 formset = BookFormSet(request.POST, instance=created_author) formset.save() #again, make sure it's valid first 

editar:

Para no tener casillas de verificación en formularios nuevos, haga esto es una plantilla:

 {% for form in formset.forms %}  {% for field in form %}  {% endfor %} {% if form.pk %} {# empty forms do not have a pk #}  {% endif %} 
{{field.label_tag}}{{field}}{{field.errors}}
Delete?{{field.DELETE}}
{% endfor %}

De hecho, me gustaría proponer un pequeño ajuste a la solución de nbv4:

Supongamos que no crea el created_author vacío fuera de la instrucción if-else y, por lo tanto, necesita anidar el formset dentro de author_form.is_valid () para evitar los errores en tiempo de ejecución cuando el author_form no es válido (y por lo tanto no se crea instancia de ningún autor).

En lugar de:

 if request.method == 'POST': author_form = AuthorModelForm(request.POST) if author_form.is_valid(): created_author = author_form.save() formset = BookFormSet(request.POST, instance=created_author) if formset.is_valid(): formset.save() return HttpResponseRedirect(...) else: ... 

Haz lo siguiente:

 if request.method == 'POST': author_form = AuthorModelForm(request.POST) if author_form.is_valid(): created_author = author_form.save(commit=False) formset = BookFormSet(request.POST, instance=created_author) if formset.is_valid(): created_author.save() formset.save() return HttpResponseRedirect(...) else: ... 

Esta versión evita comprometer el author_author hasta que book_formset haya tenido la oportunidad de validar. El caso de uso para corregir es que alguien completa un Formulario de Autor válido con un BookFormSet inválido y sigue reenviando, creando múltiples registros de Autor sin Libros asociados a ellos. Esto parece funcionar para mi aplicación de seguimiento de proyectos (reemplace “Autor” con “Proyecto” y “Libro” con “Rol”).

models.py (Contacto)

 first = models.CharField(max_length=30) middle = models.CharField('MI',max_length=30, blank=True) last = models.CharField(max_length=30) sort_order = models.PositiveIntegerField(default=99) 

models.py (Enlace)

 class Link(models.Model): contact = models.ForeignKey(Contact) link = models.URLField() description = models.CharField(max_length=30) access_date = models.DateField(blank=True,null=True) 

forms.py

 from django.forms import ModelForm from contacts.models import Contact class ContactAjaxForm(ModelForm): class Meta: model=Contact 

views.py

 def edit(request,object_id=False): LinkFormSet = inlineformset_factory \ (Contact,Link,extra=1) if object_id: contact=Contact.objects.get(pk=object_id) else: contact=Contact() if request.method == 'POST': f=forms.ContactAjaxForm(request.POST, request.FILES, instance=contact) fs = LinkFormSet(request.POST,instance=contact) if fs.is_valid() and f.is_valid(): f.save() fs.save() return HttpResponse('success') else: f = forms.ContactAjaxForm(instance=contact) fs = LinkFormSet(instance=contact) return render_to_response('contacts/edit.html', \ {'fs': fs,'f':f,'contact':contact}) 

Esto no se basa en el ejemplo del libro, sino que está editado desde algún código de mi sitio. No lo he probado, por lo que podría haber algunos errores bot en general, debería ser sólido. El uso de una instancia vacía de Contacto no es el método sugerido, pero ahorra un poco de lógica y funciona.

Editar: modelo de enlace agregado, cambiado a clave externa normal en lugar de clave externa genérica que es confusa