I have two models:
class Studio(models.Model):
name = models.CharField("Studio", max_length=30, unique=True)
class Film(models.Model):
studio = models.ForeignKey(Studio, verbose_name="Studio")
name = models.CharField("Film Name", max_length=30, unique=True)
I have a Film form that allows the user to either select a preexisting Studio, or type in a new one:
class FilmForm(forms.Form):
studio = forms.ModelChoiceField(Studio.objects, required=False)
new_studio = forms.CharField(max_length=30, required=False, label = "New Studio Name")
name = forms.CharField(max_length=30, label = "Film Name")
There's validation to assure that the new_studio name doesn't already exist. If the user enters a new_studio, I want to save the studio and then save the new Film.
form = FilmForm(request.POST)
if form.is_valid(): # All validation rules pass
std = Studio(name = form.cleaned_data['new_studio'])
std.save()
But then how do I save the Film instance subject to the brand new studio id? I've seen this question, but what if I have many more fields in the Film model and Film Form? If I use the linked answer, I would have to enter each field:
studio = Studio.objects.get(name=request.POST['new_studio'])
newFilm=Film(name=form.name, studio=studio, field_one = form.field_one, field_two = form.field_two, etc.)
What is the correct way to implement this?
Really, your only problem is that you've used a standard Form
instead of a ModelForm
. Form
doesn't have a save
method because it's not inherently tied to anything (i.e. it doesn't know what to save or where to save to).
However, if you use a ModelForm
you need to take care of all logic involved in creating a new studio in the form. This is actually better, though, because then you can just use the form and not worry about anything else: the form holds all the logic needed to properly save itself.
class FilmForm(forms.ModelForm):
class Meta:
model = Film
# only need to define `new_studio`, other fields come automatically from model
new_studio = forms.CharField(max_length=30, required=False, label = "New Studio Name")
def __init__(self, *args, **kwargs):
super(FilmForm, self).__init__(*args, **kwargs)
# make `studio` not required, we'll check for one of `studio` or `new_studio` in the `clean` method
self.fields['studio'].required = False
def clean(self):
studio = self.cleaned_data.get('studio')
new_studio = self.cleaned_data.get('new_studio')
if not studio and not new_studio:
# neither was specified so raise an error to user
raise forms.ValidationError('Must specify either Studio or New Studio!')
elif not studio:
# get/create `Studio` from `new_studio` and use it for `studio` field
studio, created = Studio.objects.get_or_create(name=new_studio)
self.cleaned_data['studio'] = studio
return super(FilmForm, self).clean()
Then, in your view, all you need is:
if form.is_valid():
form.save()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With