I have a Django view that will save the value from a Post request
form=MyForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.added_on = timezone.now()
post.save()
return redirect(index)
How do I print the invalid value which makes the is_valid() test to fail?
You can make use the .errors attribute [Django-doc] that a form has. It is a dictionary-like object that maps the name of fieds to a list of errors. For some fields the value might have multiple errors (for example a password can be too short, and not contain digits).
As specified in the documentation:
Returns a dict that maps fields to their original ValidationError
instances.
>>> f.errors.as_data()
{'sender': [ValidationError(['Enter a valid email address.'])],
'subject': [ValidationError(['This field is required.'])]}
The object also has some extra methods like .errors.as_json [Django-doc] that will convert the errors to a JSON blob.
Related
Why we use cleaned_data firstname= form.cleaned_data.get("first_name")
What is the point in this and why is it necessary?
When you call is_valid() method on a form, it results in validation and cleaning of the form data. In the process, Django creates an attribute called cleaned_data , a dictionary which contains cleaned data only from the fields which have passed the validation tests.
There 2 are two types: basic Form (forms.Form) and ModelForm (forms.ModelForm).
If you are using a ModelForm then there is no any need of using a cleaned_data dictionary because when you do form.save() it's already be matched and the clean data is saved. But you are using basic Form then you have to manually match each cleaned_data to its database place and then save the instance to the database not the form.
For example basic Form:
if form.is_valid():
ex = Example()
ex.username = form.cleaned_data['username']
ex.save()
For example ModelForm:
if form.is_valid():
form.save()
IMPORTANT: If the form pass from is_valid() stage then there is no any unvalidated data.
When data has been submitted to the database through the forms, it has to be validated or the user has to be authenticated.
When it's being returned to the user this is how it's being accessed
name = form.cleaned_data['name']
here I've used just a name but one can also use an email
When the data is returned it's returned in a more readable format.
I have a Formset made up by a Form where I exclude a required field that I want to fill programatically instead of asking the user to fill it.
My expectation is that I can exclude it from my request.POST dictionary, and add it with the line below, and that the is_valid() method will both use the request.POST data, and the initial data added to the instance passed to the form, to validate and save it.
form_kwargs={"instance": MyModel(sale=5)}
# My view.py
formset = self.get_formset(
data=self.request.POST,
form_kwargs={"instance": MyModel(sale=5)}
)
# Error here, 'sale' is not set.
if formset.is_valid():
formset.save()
The get_formset() method returns an instance of the formset.
# My formset factory method
def get_formset(self, **kwargs):
MyFormSet = forms.modelformset_factory(MyModel, form=MyForm)
...
return MyFormSet(**kwargs)
No, Django will never use initial data in place of missing posted data - otherwise how could you ever use a form to set a field to empty? Instead, you should exclude that field from the form, in which case the existing instance value will be preserved.
Either do this explicitly in the Meta class of MyForm, or pass the exclude parameter to modelformset_factory.
I am trying to create a helper function that validates forms. If the form is valid, then I will create an object in the database. The function takes in three arguments, the request, the form, and the model.
def form_validate(request, form, model):
form = form(request.POST)
print form
if form.is_valid():
print "the form is valid"
# create object using valid form
else:
print "the form is not valid"
# send back items
print form.errors.items()
If the form is valid, I want to use the form data to create a new model. How would I do that? I have tried to look at the Django docs(https://docs.djangoproject.com/en/dev/topics/forms/) but I cannot find the answer.
As David Wolever said, using ModelForms is the obvious way.
You could also pass the cleaned_data dictionary to the model constructor (assuming the fields are the same):
def form_validate(request, form, model):
form = form(request.POST)
print form
if form.is_valid():
print "the form is valid"
obj = model(**form.cleaned_data)
obj.save()
else:
# etc
However, ModelForms are really the easiest way of doing this, but you might be interested in reading Django's source to see how they work.
You'll likely want to look at ModelForms: https://docs.djangoproject.com/en/dev/topics/forms/modelforms/
What is the point in setting cd = form.cleaned_data before passing the input values of a POST/GET submission?
What is the point in this and why is it necessary? (if it is so)
It is not necessary to use the .cleaned_data attribute of a form before passing the input values, it will raise an AttributeError if you do it before calling .is_valid() in a bound form or if you try to access it in an unbound form, read more about Form.cleaned_data .
Also, it is usually a good idea to abstract the use of the form's data in a form method in order to encapsulate logic
In your views, the traditional way you should be using forms is like this:
if request.method == 'POST':
form = MyForm(request.POST) # Pass the resuest's POST/GET data
if form.is_valid(): # invoke .is_valid
form.process() # look how I don't access .cleaned_data in the view
in your form:
class MyForm(forms.Form):
my_field = forms.CharField()
def process(self):
# Assumes .cleaned_data exists because this method is always invoked after .is_valid(), otherwise will raise AttributeError
cd = self.cleaned_data
# do something interesting with your data in cd
# At this point, .cleaned_data has been used _after_ passing the POST/GET as form's data
Once is_valid() returns True, you can process the form submission safe in the knowledge that it conforms to the validation rules defined by your form. While you could access request.POST directly at this point, it is better to access form.cleaned_data. This data has not only been validated but will also be converted in to the relevant Python types for you.
Processing the data from a form
class JobForm(forms.ModelForm):
class Meta:
model = models.Job
That was my form, now trying to save it will raise an exception, and trying to validate it just fails with no errors....
job = get_object_or_404(models.Job, pk=1)
form = forms.JobForm(instance = job)
try:
form.save()
except:
print sys.exc_info()
#=>(<type 'exceptions.AttributeError'>, AttributeError("'JobForm' object has no attribute 'cleaned_data'",), <traceback object at 0x1029dbb48>)
Tried to validate it:
if form.is_valid():
form.save()
else:
print 'error'
print form.errors, len(form.errors)
#=> 'error'
#=> 0
So the form isn't valid, but the there are no errors!
Any idea?
Your form is definitely not bound. Read about Bound and Unbound forms.
From that documentation:
To bind data to a form, pass the data as a dictionary as the first parameter to your Form class constructor.
That means that also the change of a field in your model doesn't make the form bound. You have to pass those values explicitly via the constructor. But:
Note that passing an empty dictionary creates a bound form with empty data
and consider this
If you have a bound Form instance and want to change the data somehow, or if you want to bind an unbound Form instance to some data, create another Form instance. There is no way to change data in a Form instance. Once a Form instance has been created, you should consider its data immutable, whether it has data or not.
If you validate an unbound form:
It's meaningless to validate a form with no data, but, for the record, here's what happens with unbound forms:
>>> f = ContactForm()
>>> f.is_valid()
False
>>> f.errors
{}
My best guess is that you can't save a model form that has only been created with instance data (I just tried doing this with one of my forms and got the exact same error) because a form doesn't become a bound form until you pass in extra information. It doesn't really make sense to only provide data that already exists on the model to a form (and then save it again) as there wouldn't be any change. If this is coming from an html form, you should also be passing in request.POST (or request.GET) to the form.