Django ModelForm fails validation with no errors
Asked Answered
E

4

11

Ok, I have been staring at this for hours trying to figure out what's going on, to no avail. I am trying to create a ModelForm using the 'instance' keyword to pass it an existing model instance and then save it. Here is the ModelForm (stripped considerably from the original in my attempts to identify the cause of this problem):

class TempRuleFieldForm(ModelForm):
    class Meta:
        model = RuleField

and here is the code I'm running:

>>> m = RuleField.objects.get(pk=1)
>>> f = TempRuleFieldForm(instance=m)
>>> f.is_valid()
False

The model object (m above) is valid and it saves just fine, but the form will not validate. Now, as far as I can tell, this code is identical to the Django docs example found here: http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#the-save-method, though obviously I am missing something. I would greatly appreciate some fresh eyes to tell me what I've got wrong.

Thanks

Erund answered 6/10, 2010 at 5:48 Comment(1)
What does f.errors print out?Station
C
22

Note that your link doesn't call f.is_valid(), it just saves directly. This is potentially a bit misleading.

The point is that instantiating a form with just an instance parameter but no data does not bind it to data, and the form is therefore not valid. You will see that f.is_bound is False.

Behind the scenes, instance is really just the same as passing initial data, which as the docs note is only used to display the data initially and is not used for saving. You would probably benefit from reading the notes on bound and unbound forms.

Cypress answered 6/10, 2010 at 8:36 Comment(5)
+1. "instance does not imply bound": This is correct reasoning.Ataractic
Just for clarification, the reason I was using f.is_valid() was simply to make the question more concise. Using f.save() fails with an AttributeError on the cleaned_data field, which does not exist until the form validates. So even when I was using the code exactly as it is in the link I posted (using f.save() instead of f.is_valid()) it was still failing.Erund
Could someone advise how to convert the data from instance to something bound to a form... as it does not seems to be clearHousefly
@OlegTarasenko you should ask a new question, explaining exactly what you are doing and what is going wrong.Cypress
@DanielRoseman well I agree. But in the case I wanted to ask if there is a way to make the form.save() work in the example aboveHousefly
H
3

If u still want to validate the object that was in the database, you can serialize it first and then create the Form with it.

from django.utils import simplejson
from django.core.serializers import serialize

(...)

fields_dict = simplejson.loads(serialize('json', [obj]))[0]['fields']
form = forms.MyForm(fields_dict)
if form.is_valid

This is probably not the best way to do it but the only one that I have found to get a bound form from a model. I need it because I want to validate the current data in the database. I create a question since I don't think this is the best way of doing it:

Transform an unbound form to a bound one?

Haircut answered 24/1, 2012 at 20:38 Comment(1)
I was missing the whole "bind data to the form" thing, which is what you are achieving with the serialisation. I believe Django's django.forms.models.model_to_dict would be better than said serialisation though - see my answer to your question: link.Erund
G
0

This isn't a solution for OP, but it is for the post title, which is quite high in Google. So I'll post it anyway, from here:

If you're already giving request.POST to your form using request.POST or None, but it's still invalid without errors, check that there isn't any redirect going on. A redirect loses your POST data and your form will be invalid with no errors because it's unbound.

Gyral answered 7/1, 2016 at 9:40 Comment(0)
A
0

Not so much a solution for OP but this was a problem I ran into, specifically when running unit tests on ModelForms, it was a nuisance to keep on having to bind the form then also define an instance with the very same data. I created a small helper function to make things easier which others may find useful — I'm only using this for testing purposes and would be cautious to deploy it anywhere else without significant tweaks (if at all)

def testing_model_form(instance, model_form_class):
"""
A function that creates instances ModelForms useful for testing, basically takes an instance as an argument and will take care
of automatic binding of the form so it can be validated and errors checked
"""
fields = model_form_class.Meta.fields

data_dict = {}
for field in fields:
    if hasattr(instance, field):
        # The field is present on the model instance
        data_dict[field] = getattr(instance, field)
x = model_form_class(data=data_dict)
x.instance = instance
return x
Alcus answered 3/3, 2020 at 18:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.