schneck
schneck

Reputation: 10847

Form saving does not work

I'm trying to save a ModelForm as I did a thousand times before, but I'm not getting it to work. This is my Test class:

class FooForm(ModelForm):
    class Meta:
        model = Account

Now I simple get an object and save it:

a = Account.objects.all()[0]
a.save()

This works. Now I want to pass this object to the form and save it:

f = FooForm(instance=a)
f.is_valid()

... gives False. Even no errors are stored:

f.errors
{}
f.non_field_errors()
[]

Saving throws an error then:

f.save()
>>> AttributeError: 'FooForm' object has no attribute 'cleaned_data'

Any ideas?

[UPDATE]

Regarding to second's comment:

f = Form(data={}, instance=a)
f.save()
[....]
ValueError: The Account could not be changed because the data didn't validate.
f.is_valid()
>>> False
f.errors
{'user': [u'This field is required.']}
>>> a.user
<User: demo>

BTW the django documentation says, passing without data is okay, then you pass an instance:

# Create a form to edit an existing Article.
>>> a = Article.objects.get(pk=1)
>>> f = ArticleForm(instance=a)
>>> f.save()

... and could anyone please clarify the downvote? I think it's not such a strange topic.

Upvotes: 0

Views: 2046

Answers (3)

Chris Pratt
Chris Pratt

Reputation: 239430

Providing an instance to a ModelForm merely provides default values for the form. The form still expects POST data. You've given it none.

EDIT BASED ON UPDATE:

By passing an empty dataset, you've essentially reset everything to empty. Again, instance merely provides the default values for the form to display when it's first rendered. It doesn't have any impact on what final values the form will be saved with. That's where data comes in.

Try:

f = FooForm(data=a.__dict__, instance=a)
f.is_valid()

Upvotes: 1

second
second

Reputation: 28637

the form constructor needs a data argument (typically request.POST)

update

what are you actually trying to do? if you just want to change your instance in code, you don't need a form at all.

Upvotes: 2

ojii
ojii

Reputation: 4781

A form without data passed in is never valid, since there is no data, it also has no errors, since django.forms.BaseForm.full_clean (the method that is responsible for populating cleaned_data, errors and non_field_errors) doesn't actually do anything if there is no data (is_bound is False since there's no data or files).

So pass in data (a dictionary or dictionary-like-object, such as request.POST) into the form as first argument, then check is_valid again.

Upvotes: 1

Related Questions