Reputation: 4577
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 (with help from an earlier question:
class FilmForm(forms.ModelForm):
required_css_class = 'required'
studio = forms.ModelChoiceField(Studio.objects, required=False, widget = SelectWithPlus)
new_studio = forms.CharField(max_length=30, required=False, label = "New Studio Name", widget = DeSelectWithX(attrs={'class' : 'hidden_studio_field'}))
def __init__(self, *args, **kwargs):
super(FilmForm, self).__init__(*args,**kwargs)
self.fields['studio'].required = False
def clean(self):
cleaned_data = self.cleaned_data
studio = cleaned_data.get('studio')
new_studio = cleaned_data.get('new_studio')
if not studio and not new_studio:
raise forms.ValidationError("Must specify either Studio or New Studio!")
elif not studio:
studio, created = Studio.objects.get_or_create(name = new_studio)
self.cleaned_data['studio'] = studio
return super(FilmForm,self).clean()
class Meta:
model = Film
Now, my first issue is that when both studio and new_studio are missing I get a django ValueError: Cannot assign None: "Film.studio" does not allow null values error. I thought I was capturing all the errors, thus django should never get so far as to realize Film.studio is empty.
A second issue is an order of operations. What if I want to only save the new_studio after I'm sure the rest of the FilmForm is valid (thus preventing a bunch of studio names getting saved before full Film entries go through as well)? Am I in the clear or do I risk premature saving because new_studio's are saved in the form's cleaning?
Edit: Added Traceback and edited validation if-statements
Upvotes: 2
Views: 5541
Reputation: 4577
FYI on preventing the presaving of new_studio:
New def clean in form: def clean(self): cleaned_data = self.cleaned_data studio = cleaned_data.get('studio') new_studio = cleaned_data.get('new_studio')
if not studio and not new_studio:
del cleaned_data['studio'], cleaned_data['new_studio']
raise forms.ValidationError("Must specify either Studio or New Studio!")
elif not studio:
del cleaned_data['studio']
return super(FilmForm,self).clean()
And in the view:
def testone(request):
if request.method == 'POST': # If the form has been submitted...
form = FilmForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
if form.cleaned_data['new_studio']:
studio, created = Studio.objects.get_or_create(name = form.cleaned_data['new_studio'])
new_film = form.save(commit=False)
new_film.studio = studio
else:
new_film = form
new_film.save()
return HttpResponseRedirect('/') # Redirect after POST
else:
form = FilmForm() # An unbound form
return render_to_response('testone.html', {
'form': form
}, context_instance=RequestContext(request))
Upvotes: 1
Reputation: 9346
Delete studio and new_studio from cleaned_data.
if not studio and not new_studio:
del cleaned_data['studio'], cleaned_data['new_studio']
raise forms.ValidationError("Must specify either Studio or New Studio!")
Upvotes: 2