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.
Related
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.
What is the correct way to retrieve the value of a field before it is saved when the model form is submitted?
For instance, I am trying to get the field 'name' as it was before changed in the form. I was doing like below, and it works, but I am not sure that's the correct way to do it.
views.py:
if formset.is_valid():
for form in formset:
if form.has_changed and not form.empty_permitted:
cd = form.cleaned_data
new_fieldName = cd.get('name')
old_fieldName = str(cd.get('id'))
form.save()
Any suggestion?
formset.is_valid will call each form's is_valid method, which in turn will call full_clean, which calls _post_update, which updates the form's instance with the values submitted with the form. It would be too late to find references to the old values after you call formset.is_valid; you have two options:
Store copies of the instance fields before you call formset.is_valid:
saved = {}
for form in formset.forms:
saved[form.instance.pk] = form.instance.__dict__.copy()
# or keep only specific fields
Retrieve a fresh instance of the record before you call its save:
original = form._meta.model.objects.get(pk=form.instance.pk)
# compare original against form.instance and observe differences
# save your form when you're ready:
form.save()
You have also pre_save(). I use is_valid to validate any errors or restrictions to the fields and pre_save to automate processes.
Hope it helps.
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/
I have this models:
class Balanta(models.Model):
data = models.DateField()
class Conturi(models.Model):
cont=models.PositiveIntegerField()
cont_debit=models.DecimalField(default=0, max_digits=30, decimal_places=2)
cont_credit=models.DecimalField(default=0, max_digits=30, decimal_places=2)
balanta = models.ForeignKey(Balanta)
And i have formsets working ok in a template and this view:
def balanta_introducere(request):
balanta=Balanta()
ConturiInlineFormSet=inlineformset_factory(Balanta, Conturi, extra=3)
if request.method=='POST':
balanta_form=BalantaForm(request.POST, instance=balanta)
if balanta_form.is_valid():
balanta, created=Balanta.objects.get_or_create(**balanta_form.cleaned_data)
#return HttpResponseRedirect('/sitfin/balantaok')
formset=ConturiInlineFormSet(request.POST, request.FILES, instance=balanta)
if formset.is_valid():
for form in formset:
data={
'cont':form.cleaned_data.get('cont'),
'cont_debit':form.cleaned_data.get('cont_debit'),
'cont_credit':form.cleaned_data.get('cont_credit'),
'balanta':form.cleaned_data.get('balanta'),
}
try:
c=Conturi.objects.get(cont=data['cont'])
except Conturi.DoesNotExist:
cont_complete,created=Conturi.objects.get_or_create(**data)
else:
cont_complete,created=Conturi.objects.get_or_create(cont=data['cont'],cont_debit=data['cont_debit'],cont_credit=data['cont_credit'],balanta=data['balanta'])
else:
balanta_form=BalantaForm()
formset=ConturiInlineFormSet(instance=balanta)
return render_to_response('sitfin/balanta_introducere.html',{'balanta_form':balanta_form,'formset':formset}, context_instance=RequestContext(request))
If i hit the first submit, all the data goes in the database (foreignkey and all)
After the second submit with the same data, the form doesn't do anything and this is ok.
If i change a value in the form (in a "cont_credit" of a "cont" for example) and hit submit again, i get another Conturi object with only the modified "cont" with the updated "cont_credit" value and this is not good!
What is the approach for updating only some fields of an existing Conturi model with the help of a form?
Something like:
If the cont it is not in the database,
create a Conturi objects with the data in the form,
If the "cont" is already in the database,
Update the cont_credit and cont_debit data with the new values entered in the form
Thank you very much.
get_or_create is trying a get with all the parameters you pass it, so if anything changes on the form, it won't find the existing object, and instead will create a new one.
If your forms are ModelForms, then you can just use form.save() to save the instance bound to the form, and formset.save() to save all the instances bound to the formset.
EDIT:
I now noticed another thing: you are using
balanta=Balanta()
and then
balanta_form=BalantaForm(request.POST, instance=balanta)
so you are forcing the form to use a new instance. try getting the specific Balanta you're editing, and pass that as the instance.
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