I am trying to find a simple way to create a form that allows the editing of two models with foreign key relationship simultaneously.
After some research, it seems that Inline formsets come very close to what I want to do.
The django documentation offers this example:
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
And then,
>>> from django.forms import inlineformset_factory
>>> BookFormSet = inlineformset_factory(Author, Book, fields=('title',))
>>> author = Author.objects.get(name='Mike Royko')
>>> formset = BookFormSet(instance=author)
Let’s suppose Author
has a second field, city
. Can I use the fields
argument to add a city to the form?
If inline formsets are not the way to go, is there another way that generates this joint form?
After some more research, I found django model Form. Include fields from related models from 2009 which hints that inline form sets might not be the way to go.
I would be very much interested if there’s a default solution with a different factory.
Advertisement
Answer
Well, this is a bit different from the linked post because there the relationship is a OneToOne
and not a ForeignKey
.
There is no django factory (at least that I know of) to do what you want automatically. You can try the following instead:
Create a
ModelForm
for the depended table (Book
in this case):JavaScript151class BookForm(forms.ModelForm):
2class Meta:
3model = Book
4fields = ['name', 'city', 'other_field', ]
5
Create an
inline_formset
for the depended table:JavaScript121BookFormSet = inlineformset_factory(Author, Book, form=BookForm)
2
Use the formset in your view:
JavaScript110101def my_view(request):
2if request.method == 'POST':
3formset = BookFormSet(request.POST, instance=request.user)
4if formset.is_valid():
56formset.save()
7else:
8formset = BookFormSet(instance=request.user)
9return render_to_response("template.html", {"formset": formset})
10
OR in a class based view: django class-based views with inline model-form or formset
Finally in the template (this part needs a bit of fumbling to get it right, but this is a general idea):
JavaScript171<form action="." method="post">
2{% csrf_token %}
3{{ formset }}
4{{ formset.management_form }}
5<input type="submit" value="Submit">
6</form>
7