Multiple models in one form


#1

I am having a hard time conceptualizing something here. My takeaway from the models tutorial is that it is best to have separate models instead of one large one. For example, I created the Thing model, but now I want to have some more detail around, say, the Company associated with the Thing. How do I approach this so that in my edit_thing.html a user can edit both the Thing and the Company information? Would this be two different forms within the template? Or one form that includes both models? Or…two different templates?

models.py

class Company(models.Model):
	name = models.CharField(max_length=255)
	tagline = models.CharField(max_length=255)
	website = models.URLField()

class Thing(models.Model):
	name = models.CharField(max_length=255) 
	description = models.TextField(max_length=255)
	slug = models.SlugField(unique=True)
	user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True) 
	address = models.CharField(max_length=50)
	city = models.CharField(max_length=60)
	state_province = models.CharField(max_length=30)
	country = models.CharField(max_length=50)
	company = models.ForeignKey(Company, on_delete=models.CASCADE, blank=True, null=True)

	def __str__(self): 
		return self.name

views.py

@login_required
def edit_thing(request, slug):
	# grab the object...
	thing = Thing.objects.get(slug=slug)
	
	if thing.user != request.user: 
		raise Http404

# set the form we're using...
form_class = ThingForm

# if we're coming to this view from a submitted form,
if request.method == 'POST':
	# grab the data from the submitted form
	form = form_class(data=request.POST, instance=thing) 
	if form.is_valid():
		# save the new data
		form.save()
		return redirect('thing_detail', slug=thing.slug)
# otherwise just create the form
else:
	form = form_class(instance=thing)
# and render the template
return render(request, 'things/edit_thing.html', { 
	'thing': thing,
    'form': form,
})

forms.py

class CompanyForm(ModelForm):
	class Meta:
		model = Company
		fields = ('name', 'website', 'tagline')

What’s the best way of creating a form so I can edit both the Thing and the Company in the same template?


#2

Great question! This is definitely where programming gets “fun” because there isn’t any one right answer.

For WeddingLovely (my startup), I split my edit pages up so there was one page for editing the social media info, one page for adding images, one page for editing company information, etc — I did this because the amount of fields on the “edit” page was getting overwhelming. (And then I made a dashboard with links to all those pages.) This is also probably the simplest way because then you can just use ModelForms.

You can indeed do a form that edits both though, if you think the user experience is better! I found this Stack Overflow question that kind of goes into how to do that: https://stackoverflow.com/questions/2770810/multiple-models-in-a-single-django-modelform

So, create two modelforms in your forms.py. Then initialize both forms in your view (form_class = ThingForm, and add company_form_class = CompanyForm for example) and pass into the template. And in if request.method == 'POST':, you duplicate that code — do what you’re doing for the thing class, and then do it for the company information as well.

I hope that makes sense! Let me know if I can clarify. :D