I have a model with a PositiveIntegerField in my Django application (views):
class Post(models.Model):
author = models.ForeignKey('UserProfile')
creation_date = models.DateTimeField(auto_now_add=True)
views = models.PositiveIntegerField(default=0)
tags = models.ManyToManyField('Tag', through="PostTagging", null=False, blank=False)
rating = models.FloatField(default=0)
However, when I test it, it accepts negative values:
Test:
def test_post_with_negative_views(self):
test_user = User.objects.get(username='test_student')
test_user_profile = UserProfile.objects.get(user=test_user)
post = Post.objects.create(author=test_user_profile, title='Django Testing', content='hello world', views=-10)
self.assertEquals(post.views, 0)
Fail:
Creating test database for alias 'default' ...
......F.......
=====================================================================
FAIL: test_post_with_negative_views (bark.tets.PostTest)
---------------------------------------------------------------------
Traceback (most recent call last):
File "/home/ewan/Documents/WAD2/studeso/bark/bark/tests.py", line 58, in test_post_with_negative_views
self.assertEquals(post.views, 0)
AssertionError: -10 != 0
---------------------------------------------------------------------
FAILED (failures=1)
Am I doing something wrong here?
I've tried testing it with int(-10) and int("-10") incase it was a string formatting error I get a lot.
catavaran's answer including:
post.full_clean()
also fails.
Here is the excerpt from the validating objects chapter of the docs:
Note that
full_clean()
will not be called automatically when you call your model’ssave()
method. You’ll need to call it manually when you want to run one-step model validation for your own manually created models.
So validating and saving model should look like this:
post = Post(author=test_user_profile, title='Django Testing',
content='hello world', views=-10)
post.full_clean()
post.save()
UPDATE: Seems like this validation is turned off for SQLite backend. I found this code in the django.db.backends.sqlite3.operations.DatabaseOperations
class.
def integer_field_range(self, internal_type):
# SQLite doesn't enforce any integer constraints
return (None, None)
Values from this method are used to build validators for PositiveIntegerField
.
As far as I understand this is done for compatibility reasons. So if you want to work with SQLite then you have to manually add the validator:
from django.core.validators import MinValueValidator
class Post(models.Model):
...
views = models.PositiveIntegerField(default=0,
validators=[MinValueValidator(0)])
After this modification the full_clean()
should work as expected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With