Reputation: 128
I have a some models with inheritance that look something like this:
Class A(models.Model):
some_text = models.CharField(max_length=100)
#other fields, not important
Class B(A):
some_int = models.IntegerField(blank=True, null=True, validators=[MinValueValidator(1), MaxValueValidator(1000)])
Then I fire up the Django shell and do the following:
>>> obj = B()
>>> obj.some_text = 'foo'
>>> obj.some_int = 'bar'
>>> obj.full_clean()
And naturally I get:
>>> ValidationError: {'some_int': [u"'bar' value must be an integer."]}
Good. Then:
>>> obj.some_int = ' ' #whitespace
>>> obj.full_clean()
And I get:
>>> ValidationError: {'some_int': [u"' ' value must be an integer."]}
Perfect. But then I try an empty string:
>>> obj.some_int = '' #empty string
>>> obj.full_clean()
No ValidationError is raised, but if I try to save the object:
>>> obj.save()
I get:
>>> ValueError: invalid literal for int() with base 10: ''
What's going on here? Is this correct behavior? How is Django checking to see if the value is a valid integer?
I really don't want to customize my model's clean() function to check for this, but it's starting to look like I have no choice.
EDIT: Django 1.6.5, Python 2.7.6, Windows 7 64 bit.
Upvotes: 3
Views: 2282
Reputation: 5194
the reason of this behavior is commented in clean_fields method :
def clean_fields(self, exclude=None):
"""
Cleans all fields and raises a ValidationError containing message_dict
of all validation errors if any occur.
"""
if exclude is None:
exclude = []
errors = {}
for f in self._meta.fields:
if f.name in exclude:
continue
# Skip validation for empty fields with blank=True. The developer
# is responsible for making sure they have a valid value.
raw_value = getattr(self, f.attname)
if f.blank and raw_value in f.empty_values:
continue
try:
setattr(self, f.attname, f.clean(raw_value, self))
except ValidationError as e:
errors[f.name] = e.error_list
if errors:
raise ValidationError(errors)
Upvotes: 5
Reputation: 48962
You're getting this behavior because you have blank=True
. I agree with you that the behavior you're seeing is strange - it's a symptom of the fact that in Django model validation is tied up quite tightly with form validation, even though in principle they can be separate.
Assuming that you actually want blank=True
and null=True
, I wouldn't worry about this. Forms will do the right thing (convert the empty string in a form to a NULL
value in the database), and the model and database won't actually let you save the invalid value. The only issue is that if you have data entry that doesn't involve Django forms, the error will get thrown at save()
time rather than at full_clean()
time.
Of course, if you don't want to allow NULL
values for the field, just set blank=False, null=False
and full_clean()
will complain about the empty string just like you expect.
Upvotes: 2
Reputation: 2790
Well that is because you allowed your field to be blank (and also null). so it is okay and it is valid.
If you don't want it to be that way, just remove the blank=True
option or change it to blank=False
Upvotes: 0