noobes
noobes

Reputation: 161

Django error: ValueError

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

Answers (3)

catherine
catherine

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

Martin B.
Martin B.

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

Daniel Roseman
Daniel Roseman

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

Related Questions