Reputation: 161
I have two models and im doing a customform so that I may be able to view and save the form from my html into db. but when I try to save then I get this error.
Traceback
Environment:
Request Method: POST
Request URL: http://127.0.0.1:8008/
Django Version: 1.4
Python Version: 2.7.3
Installed Applications:
('django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'SecondBlog.blog',
'django.contrib.admin',
'django.contrib.admindocs')
Installed Middleware:
('django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware')
Traceback:
File "c:\Python27\lib\site-packages\django\core\handlers\base.py" in get_response
111. response = callback(request, *callback_args, **callback_kwargs)
File "f:\apt3\SecondBlog\SecondBlog\blog\views.py" in home
10. if form.is_valid():
File "c:\Python27\lib\site-packages\django\forms\forms.py" in is_valid
124. return self.is_bound and not bool(self.errors)
File "c:\Python27\lib\site-packages\django\forms\forms.py" in _get_errors
115. self.full_clean()
File "c:\Python27\lib\site-packages\django\forms\forms.py" in full_clean
272. self._post_clean()
File "c:\Python27\lib\site-packages\django\forms\models.py" in _post_clean
309. self.instance = construct_instance(self, self.instance, opts.fields, opts.exclude)
File "c:\Python27\lib\site-packages\django\forms\models.py" in construct_instance
51. f.save_form_data(instance, cleaned_data[f.name])
File "c:\Python27\lib\site-packages\django\db\models\fields\__init__.py" in save_form_data
454. setattr(instance, self.name, data)
File "c:\Python27\lib\site-packages\django\db\models\fields\related.py" in __set__
366. self.field.name, self.field.rel.to._meta.object_name))
Exception Type: ValueError at /
Exception Value: Cannot assign "u'Sasa'": "Book.author" must be a "Author" instance.
models.py
class Author(models.Model):
name = models.CharField(max_length = 30)
class Book(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(max_length = 100)
def __unicode__(self):
return '%s' % (self.title)
forms.py
class CustomForm(ModelForm):
author = forms.CharField()
def save(self, commit=True):
author = Author.objects.get_or_create(name=self.cleaned_data['author'])
instance = super(CustomForm, self).save(commit=commit)
instance.author = author
if commit:
instance.save()
return instance
class Meta:
model = Book
fields = ('author','title',)
views.py
def home(request):
if request.method == 'POST':
form = CustomForm(request.POST)
if form.is_valid():
print "all validated"
form.save()
return HttpResponseRedirect('index.html')
else:
print "failed"
else:
form = CustomForm()
variables = RequestContext(request, {'form' : form})
return render_to_response('index.html', variables)
Thank you so much.
Upvotes: 1
Views: 2892
Reputation: 22808
I try your codes and do some tests, no matter what I do I always get that error. Because before the author create, the book execute first which cause the instance error.
I modified your codes. I remove your save method and change it to clean method which is working now.
class CustomForm(forms.ModelForm):
author = forms.CharField()
def clean(self):
cleaned_data = super(CustomForm, self).clean()
author = cleaned_data.get("author")
if not author:
raise forms.ValidationError("Please enter an author")
data = Author.objects.create(name=author)
cleaned_data['author'] = data
return cleaned_data
class Meta:
model = Book
fields = ('author','title',)
Upvotes: 2
Reputation: 1928
The issue is not with the saving, but with the validating of your form. Basically, you create a customized version of the model form for Book, with two fields, author
and title
. By default, the author
field would display as a reference browsing widget for the Author type.
However, what you do with author = forms.CharField()
is tell the form to display a simple text input field instead of an Author reference selector. When it tries to validate this.. well it can't.
What you need to do is process the author
value before validating, you can do this in the clean()
function, which you can add to your CustomForm
def clean(self):
self.cleaned_data['author'] = Author.objects.get_or_create(name=self.cleaned_data['author'])
return self.cleaned_data
A very similar question is in how to change form field in method is_valid()
Upvotes: 3
Reputation: 599956
The problem is that it isn't even getting to your code that sets the author instance, because the superclass's save method is setting it there using the text field, which is where the error occurs.
You could try either using pop
to remove the author
value from cleaned_data
before calling super, or replacing that value with the Author instance.
Edit for example
def save(self, commit=True):
author = Author.objects.get_or_create(name=self.cleaned_data.pop('author'))
instance = super(CustomForm, self).save(commit=commit)
Upvotes: 0