I have a Django form that allows a user to change their password. I find it confusing on form error for the fields to have the *'ed out data still in them.
I've tried several methods for removing form.data, but I keep getting a This QueryDict instance is immutable exception message.
Is there a proper way to clear individual form fields or the entire form data set from clean()?
Regarding the immutable QueryDict error, your problem is almost certainly that you have created your form instance like this:
form = MyForm(request.POST)
This means that form.data is the actual QueryDict created from the POST vars. Since the request itself is immutable, you get an error when you try to change anything in it. In this case, saying
form.data['field'] = None
is exactly the same thing as
request.POST['field'] = None
To get yourself a form that you can modify, you want to construct it like this:
form = MyForm(request.POST.copy())
Someone showed me how to do this. This method is working for me:
post_vars = {}
post_vars.update(request.POST)
form = MyForm(post_vars, auto_id='my-form-%s')
form.data['fieldname'] = ''
form.data['fieldname2'] = ''
If you need extra validation using more than one field from a form, override the .clean() method. But if it's just for one field, you can create a clean_field_name() method.
http://docs.djangoproject.com/en/1.1/ref/forms/validation/#ref-forms-validation
I just created the form again.
Just try:
form = AwesomeForm()
and then render it.
Django has a widget that does that:
https://docs.djangoproject.com/en/1.8/ref/forms/widgets/#passwordinput
now if you are not working with passwords you can do something like this:
class NonceInput(Input):
"""
Hidden Input that resets its value after invalid data is entered
"""
input_type = 'hidden'
is_hidden = True
def render(self, name, value, attrs=None):
return super(NonceInput, self).render(name, None, attrs)
Of course you can make any django widget forget its value just by overriding its render method (instead of value I passed None in super call.)
Can't you just delete the password data from the form's cleaned_data during validation?
See the Django docs for custom validation (especially the second block of code).
I guess you need to use JavaScript to hide or remove the text from the container.
Related
I have a Model with 5 fields. I create a ModelForm on top of that model, now I intialize the form with request data containing 4 fields.
The reason of 4 fields in request data is the checkbox on frontend that isn't passed using jquery FormData when unchecked.
Now the problem is, I want to set a default value of the 5th field at the time of form initialization if checkbox is not passed in request data.
What would be the best thing to do, set default value in ModelForm or Form or use default value from Model or I can set the value of a specific field.
Sugesstions are welcome. TIA.
You can mess around with request.POST before binding it to the form. If you are using CBV FormView you can subclass get_form_kwargs. Something like
# UNTESTED CODE
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
if self.request.method in ('POST', 'PUT'):
if 'foo' not in kwargs['data']:
#this starts as request.POST which is an immutable QueryDict
data = kwargs['data'].copy() # mutable copy
data['foo'] = 'whatever' #supply the missing default value
kwargs['data'] = data
return kwargs
Consult the Django documentation w.r.t. QueryDict. They are tricky beasts that are directory-like but the differences can be enough to catch you out. It's easy to create one at the shell prompt and play with it to make sure you get this right.
I have a problem. I looked at the web for a solution but did not find one. If my problem already have an answer, please give me the links.
The Problem
Here is the problem:
I create a form inside one of my view with some initial values:
form = MyForm(initial=initial)
However, I do not have a full control over these initial values, thus I need to check is the form is valid. However, because the form in unbound .is_valid() always return False.
So, I tried to create an bound form from the first step:
form = MyForm(initial)
However, I do not initialize all the field, simply because I do not know their name and how many they are, thus I cannot initialize all of them.
The problem is that some of the field I do not initialize are required. Thus, the .is_valid() always return False because I do not provide required field(s).
What I know is that all of the required field have a default value.
When I created the form with initial values (i.e. MyForm(initial=initial)), the defaults value are provided. So I wish I could do something like:
form = MyForm(initial=initial)
form = MyForm(form)
However, that obviously doesn't work.
I see two potential solution to my problem:
Validate an unbound form
Get a list with all the fields and their default values (if one) (I do not know this list in advance)
I do not know how to make 2, however, I tried this for 1:
form = MyForm(initial=initial)
form.clean()
form.clean() calls a custom function where I stated (I had no problem with a bound form):
cleaned_date = super().clean()
That returns the following errors:
AttributeError at XXX
'MyForm' object has no attribute 'cleaned_data'
And well, that is kind of logical, the form is unbound, thus the data are not cleaned yet.
Any piece of advice (or complete solution) will be greatly appreciated.
Thank you for having reading me.
Wrong Solution (that works, but too wordly/ugly)
There is one solution to this problem but I am sure this is not the could one (it is way too ugly).
I first create a unbound field:
form = MyForm()
Then I read the initial value of the fields inside the string representation of the form.
for field in form:
index_name = str(field.find("name"
name = field[index_name+len('name="':]
name = name[:name.find('"')]
index = str(field).find("value")
if index >= 0: # if their is a default value
value = field[index+len('value="'):]
value = value[:value.find('"')]
initial[name] = value
Then I just need to remake the form, bound this time:
form = MyForm(initial)
However, this solution is overwhelming and I am sure there is a better way to go.
Ideally you would get the default values and do an initial.update(defaults) and hand it to the form.
If the defaults are not available to you, you can try to remove fields from the form that are not in initial.
form = MyForm(data=initial)
field_keys = list(form.fields.keys())
for field_name in field_keys:
if field_name not in initial:
form.fields.pop(field_name)
form.is_valid() # <- only validates fields in initial
Maybe you can initialize your form with your initial values with no full control, and run form.is_valid() and use the form.cleaned_data to initial another form? But Why would you have to do validating on the unbound form? I think this scenario is rare.
I need to overwrite the clean() method in a Django Model form to perform additional uniqueness checks on the data entered.
This page gives implementation details:
https://docs.djangoproject.com/en/1.11/ref/forms/validation/ Copied here:
def clean(self):
cleaned_data = super(ContactForm, self).clean()
cc_myself = cleaned_data.get("cc_myself")
subject = cleaned_data.get("subject")
if cc_myself and subject:
# Only do something if both fields are valid so far.
if "help" not in subject:
raise forms.ValidationError(
"Did not send for 'help' in the subject despite "
"CC'ing yourself."
)
However I'm confused why this method doesn't return cleaned_data at the end of the function? Surely that is the correct thing to do?
Have a look at django's _clean_form method:
def _clean_form(self):
try:
cleaned_data = self.clean()
except ValidationError as e:
self.add_error(None, e)
else:
if cleaned_data is not None:
self.cleaned_data = cleaned_data
Read the last bullet point on the forms doc and especially this bit of the ModelForm doc.
If the clean method raises a ValidationError, the error gets added to the forms' errors.
If the clean method has returned anything and threw no errors, the form is going to use that for its cleaned_data attribute. Otherwise it will keep its 'old' one.
In your case, all that your clean method does, is validating an aspect of the form.
The example you are interested in is an override of the clean method for related fields. This means that it validates a logic that implicate more than one field. Consider this as the form's clean method. Thus, you don't want to return any values in this case.
As the doc says :
"Be careful when doing this in practice, since it can lead to confusing form output. We’re showing what is possible here and leaving it up to you and your designers to work out what works effectively in your particular situation."
It depends on your particular case, but in my experience with overriding clean on one particular field, you'll want to return it if the validation passes. Again, this is for only one field.
Here's another example from the doc, but for one field validation:
def clean_recipients(self):
data = self.cleaned_data['recipients']
if "fred#example.com" not in data:
raise forms.ValidationError("You have forgotten about Fred!")
# Always return a value to use as the new cleaned data, even if
# this method didn't change it.
return data
In Django < 1.7, form.clean() was required to return a dictionary of cleaned_data.
This method may still return a dictionary of data to be used, but it’s no longer required.
I have a form with a foreign key field. The field is disabled and I initialized the value with initial. The value shows up but when I submit it, an error shows up: 'This field is required'
views.py:
def updateTicket(request, ticket_id):
ticketDetails = editTicket1.objects.filter(ticketID=ticket_id).last()
updateTrouble = editTrouble(request.POST or None, instance=ticketDetails, initial={'ticketID': ticket_id})
if updateTrouble.is_valid():
updateTrouble.save()
forms.py:
ticketID = forms.ModelChoiceField(queryset=tblTicket.objects.all(),widget=forms.Select(attrs={'disabled':'disabled'}))
How come when I disable the field, a foreign key field, the server does not accept the value. Even with initialization, when posted, it submits a blank value.
from thee django docs, it states this for the form field: "By default, each Field class assumes the value is required, so if you pass an empty value – either None or the empty string ("") – then clean() will raise a ValidationError exception:"
So, instead you should have done this; ticketID = forms.ModelChoiceField(required:False, queryset=tblTicket.objects.all(),widget=forms.Select(attrs={'disabled':'disabled'}))
or in your Models you'd have set a blank argument to the field to False, but I'll suggest to do it in the Form.
No sure if this is the issue but I think your form will always by showing the ticket_id since this is given in the initial form option which overrides the instance.
It's described here in the docs: https://docs.djangoproject.com/en/1.8/topics/forms/modelforms/#providing-initial-values
Also - if you want to correctly process the form I think you should expand the update ticket function like it is described in the docs:
https://docs.djangoproject.com/en/1.8/topics/forms/#the-view
The difference between the above example and your code will be in the else statement where instead of a blank form you initiate it using initial data like you provided in your code.
Hope that helps!
I have a form, which i am rendering. It also allow user to add a new instance if it does not exist in the list.
lets say the field is name from category modal.
name is an drop down list, and if user does not find his value in the list, he writes the name in the next input box.
When i validate it, it fails. because its not an instance of category.
Then I got it by using self.data and i compare if its an Integer, or not?
If its an integer, than its simply an existing element, if not, the user might have chosen a new User, and thus by getting it from the self.data, i can create the
category
object and save it and replace the original value with the ID so that validation does not fail.
Problem.
I know using self.data and using it for a db query can be dangerous. As user is allowed to input anything in it, and it might empty my database with that query, (i have heard it like that). Is this really possible? if yes, how to avoid that.
Hope someone can give me an idea.
Suppose your form has a name field for existing category names and a new_name field for the input box. In your form's clean() method, you'll want to check to see if self.cleaned_data has a value for new_name and act accordingly. You might do:
self.cleaned_data['name'] = self.cleaned_data['new_name']
for example.
Unless you override other field or form methods, the data in these fields are 'safe' as far as malicious input is concerned. If you raise a ValidationError in the form's clean() method, is_valid() will return false. So, as long as you:
form = YourForm(...)
if form.is_valid():
form.save()
The save() will not be called with invalid data.