I have a queryset in order to check if the result is Null or exists
cupon_existente = Orden.objects.filter(user = self.request.user, ordenado= False).values_list('promo', flat=True)
when the result is 'None' and I want to validate like this:
if cupon_existente:
True
else:
False
it validates as 'True'
how can I validate that None is actually 'False' or 'NULL' ?
what I did to catch the None as empty or null was:
if cupon_existente is None:
messages.warning(self.request, "Ya tiene un cupĆ³n aplicado")
return redirect("pago-cupon")
I added the is None validation
Related
In the model I set:
class Task(models.Model):
EstimateEffort = models.PositiveIntegerField('Estimate hours',max_length=200)
Finished = models.IntegerField('Finished percentage',blank=True)
But in the web page, if I didn't set a value for the Finished field, it is showing an error This field is required. I tried null=True and blank=True. But none of them worked. So could you please tell me how can I make a field allowed to be empty.
I have found that there is a attribute empty_strings_allowed, i set it to True, but still the same, and i subclass the models.IntegerField. It still can not work
class IntegerNullField(models.IntegerField):
description = "Stores NULL but returns empty string"
empty_strings_allowed =True
log.getlog().debug("asas")
def to_python(self, value):
log.getlog().debug("asas")
# this may be the value right out of the db, or an instance
if isinstance(value, models.IntegerField):
# if an instance, return the instance
return value
if value == None:
# if db has NULL (==None in Python), return empty string
return ""
try:
return int(value)
except (TypeError, ValueError):
msg = self.error_messages['invalid'] % str(value)
raise exceptions.ValidationError(msg)
def get_prep_value(self, value):
# catches value right before sending to db
if value == "":
# if Django tries to save an empty string, send to db None (NULL)
return None
else:
return int(value) # otherwise, just pass the value
Use
Finished = models.IntegerField('Finished percentage', blank=True, null=True)
Read https://docs.djangoproject.com/en/1.4/ref/models/fields/#blank:
null is purely database-related, whereas blank is validation-related.
You might have defined the field without null=True first. Changing that in the code now won't change the initial layout of the database. Use South for database migrations or change the database manually.
On a form you could set required=False on the field:
Finished = forms.IntegerField(required=False)
Or to avoid redefining the field on a ModelForm,
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.fields['Finished'].required = False
#self.fields['Finished'].empty_label = 'Nothing' #optionally change the name
Maybe a default value is needed
finished = models.IntegerField(default=None,blank=True, null=True)
I see that forms.ChoiceField is using this code to validate the value:
def validate(self, value):
"""
Validates that the input is in self.choices.
"""
super(ChoiceField, self).validate(value)
if value and not self.valid_value(value):
raise ValidationError(
self.error_messages['invalid_choice'],
code='invalid_choice',
params={'value': value},
)
def valid_value(self, value):
"Check to see if the provided value is a valid choice"
text_value = force_text(value)
for k, v in self.choices:
if isinstance(v, (list, tuple)):
# This is an optgroup, so look inside the group for options
for k2, v2 in v:
if value == k2 or text_value == force_text(k2):
return True
else:
if value == k or text_value == force_text(k):
return True
return False
and forms.models.ModelChoiceField this code:
def validate(self, value):
return Field.validate(self, value)
Q1. Why Django uses validation to check if the selected value (from dropdown) is indeed in the choice list for forms.ChoiceField?
Q2. When Django uses the validation from Q1, to check if the value is indeed in the choice list, why does not also check if the selected value is in the model records for forms.models.ModelChoiceField?
The validation process starts from form.full_clean() where you have form._clean_fields() and form._clean_form executed in this order.
Now if you take a closer look at what form._clean_fields() do, you will probably notice that it only calls field.clean(value, initial) and collects the results into a cleaned_data dict. So the interesting part is at field.clean, lets see what happens there:
def clean(self, value):
"""
Validate the given value and return its "cleaned" value as an
appropriate Python object. Raise ValidationError for any errors.
"""
value = self.to_python(value)
self.validate(value)
self.run_validators(value)
return value
First, we have a to_python call, followed by validate and finishing with run_validators.
So in terms of ModelChoiceField when you reach the .validate method, your choice is already a Model instance, thats why, this kind of validation (from Q2) is happening inside the to_python method.
def to_python(self, value):
if value in self.empty_values:
return None
try:
key = self.to_field_name or 'pk'
value = self.queryset.get(**{key: value})
except (ValueError, TypeError, self.queryset.model.DoesNotExist):
raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice')
return value
one thing i can say is for forms.ChoiceField the input are coming from the user perspective means a user can use inspect element and enter a choice which doesnt appear from the backend .
but for models one the choices are directly coming from the backend or the database
After checking my form is valid I perform additional validation:
def reset_passwd(req):
if req.method == 'POST':
form = ResetPasswdForm(req.POST)
if form.is_valid():
# extract data
passwd1 = form.cleaned_data['passwd1']
passwd2 = form.cleaned_data['passwd2']
# validate passwd
if passwd1 != passwd2:
raise forms.ValidationError('passwords are not the same', 'passwd_mismatch')
# do stuff...
return HttpResponseRedirect('/success')
else:
form = ResetPasswdForm(req.POST)
return render(req, 'reset_passwd_form.html', {'form': form})
Problem is raising a ValidationError which is an Exception of course breaks execution of the view function so no response is returned!
How is one suppose to return their bound form showing validation errors for validation not performed by form.is_valid()?
(The confusing thing is the django documentation say form.is_valid() throws ValidtionErrors if the form is invalid, however it must handel them as debugging it execution continues when is_valid() is false.)
To validate such cases, you should use clean() method of a form, rather than raising an error in the view.
This is nicely explained at Cleaning and validating fields that depend on each other
You need to override the is_valid() method, call the super is_valid() first ( return false if it returns false ), and then handle your error case.
If you use clean() instead you won't benefit for things such as "required=True" in your other fields and will need to check everything manually.
super().clean() just ... does not check for it afaik, and it could give you KeyError when accessing cleaned_data['passwd1'] unless checking it yourself.
class MyResetPasswdForm(forms.Form):
passwd1 = forms.CharField(widget=forms.PasswordInput, required=True)
passwd2 = forms.CharField(widget=forms.PasswordInput, required=True)
def is_valid(self):
valid = super(MyResetPasswdForm).is_valid()
if not valid:
return valid
if self.cleaned_data.get("passwd1") != self.cleaned_data.get("passwd2"):
# You cannot raise a ValidationError because you are not in the clean() method, so you need to add the error through the add_error method.
self.add_error("passwd2", ValidationError('passwords are not the same', 'passwd_mismatch')
# You could also use None instead of "passwd2" if you do not want the error message to be linked to the field.
if not self.errors:
return True
return False
This way, you get the pre-set error messages, django handles the fields requirements when you call the super().is_valid().
So I created a custom form field to validate for duplicate usernames. I'm using Django + Mongoengine as my database. I have that plugged and working with the django authentication system so I'm assuming it can be accessed from forms.py? Maybe that assumption is incorrect. So I have the field
class UsernameField(CharField):
def to_python(self, value):
if not value:
return ""
return value
def validate(self, value):
super(CharField, self).validate(value)
try:
# If the user object exists it won't throw an Error/Exception
user=User.objects.get(username=value)
raise ValidationError("Username already exists")
except:
pass
But when I actually use it in my form, it always seems to validate correctly even though I've called checked if form.is_valid() is True
You're raising exceptions in the try block but then snuffing them out in the except block with pass. Try this, it will check for the existing user and only fails if it exists.
try:
# If the user object doesn't exist, it validates
user=User.objects.get(username=value)
except django.core.exceptions.DoesNotExist:
pass
else:
#user does exist, barf.
raise ValidationError("Username already exists")
Bah, it was a dumb mistake on my part. For some reason I forgot that the Error I was trying to raise would be caught by the try and I would get sent to the except route. Changing it to this works
class UsernameField(CharField):
def to_python(self, value):
if not value:
return ""
return value
def validate(self, value):
super(CharField, self).validate(value)
usernameDuplicate = False
try:
# If the user object exists it won't throw an Error/Exception
user=User.objects.get(username=value)
usernameDuplicate = True
except:
pass
if usernameDuplicate==True:
raise ValidationError("Username already exists")
I have a form where none of the fields are required indivdually, but I want to raise a validation error if all fields are left empty. What is the best way to do this? I tried the following but it it didn't work:
def clean(self):
cleaned_data = super(SearchForm, self).clean()
if len(cleaned_data) == 0:
raise forms.ValidationError(ugettext_lazy("You must fill at least one field!"))
Rather than checking the length of the cleaned_data (it should always contain one entry for each form field), you should check each entry and confirm that the values are all empty.
Here's an example of how you could do it.
def clean(self):
cleaned_data = super(SearchForm, self).clean()
form_empty = True
for field_value in cleaned_data.itervalues():
# Check for None or '', so IntegerFields with 0 or similar things don't seem empty.
if field_value is not None and field_value != '':
form_empty = False
break
if form_empty:
raise forms.ValidationError(ugettext_lazy("You must fill at least one field!"))
return cleaned_data # Important that clean should return cleaned_data!
Ignore fields filled with just whitespace as well: and not field_value.isspace()