Allow only positive decimal numbers
Question:
Within my Django models I have created a decimal field like this:
price = models.DecimalField(_(u'Price'), decimal_places=2, max_digits=12)
Obviously it makes no sense for the price to be negative or zero. Is there a way to limit the decimal number to only positive numbers?
Or do I have to capture this using form validation?
Answers:
Use the MinValueValidator
.
price = models.DecimalField(_(u'Price'), decimal_places=2, max_digits=12, validators=[MinValueValidator(Decimal('0.01'))])
You could do something like this :
# .....
class priceForm(ModelForm):
price = forms.DecimalField(required=False, max_digits=6, min_value=0)
This, also, is responsible for the validator value of ‘price’.
According to the docs, it seems that there’s no way to put something like a database constraint on a field. The best you can do is add model “validators” which will be called if you call model validation or use a ModelForm
. The validators are skipped if you simply put values into an object and save()
.
So, you can add validation on the forms or you can add validation to the model which also get run on the form level if you use ModelForm
.
From the docs on “How validators are run”:
See the form validation for more information on how validators are run
in forms, and Validating objects for how they’re run in models. Note
that validators will not be run automatically when you save a model,
but if you are using a ModelForm
, it will run your validators on any
fields that are included in your form. See the ModelForm documentation
for information on how model validation interacts with forms.
In Django 2.2 you can add constraints to a model which will be applied in the migrations as a constraint on the database table:
from decimal import Decimal
from django.db import models
class Item(models.Model):
price = models.DecimalField( _(u'Price'), decimal_places=2, max_digits=12 )
class Meta:
constraints = [
models.CheckConstraint(check=models.Q(price__gt=Decimal('0')), name='price_gt_0'),
]
Validation of Constraints
In general constraints are not checked during full_clean()
, and do not raise ValidationErrors
. Rather you’ll get a database integrity error on save()
.
Assuming this is your product model, and you want to add non-negative constraint on price field. You can add the meta constraint on the model:
class Product(models.Model):
price = models.DecimalField(max_digits=13, decimal_places=2)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
managed = True
db_table = 'product'
constraints = [
models.CheckConstraint(check=models.Q(price__gte='0'), name='product_price_non_negative'),
]
- Import dependencies
from decimal import Decimal
from django.core.validators import MinValueValidator
- Add validators
price = models.DecimalField(
decimal_places=2,
max_digits=12,
validators=[MinValueValidator(Decimal('0.01'))]
)
Within my Django models I have created a decimal field like this:
price = models.DecimalField(_(u'Price'), decimal_places=2, max_digits=12)
Obviously it makes no sense for the price to be negative or zero. Is there a way to limit the decimal number to only positive numbers?
Or do I have to capture this using form validation?
Use the MinValueValidator
.
price = models.DecimalField(_(u'Price'), decimal_places=2, max_digits=12, validators=[MinValueValidator(Decimal('0.01'))])
You could do something like this :
# .....
class priceForm(ModelForm):
price = forms.DecimalField(required=False, max_digits=6, min_value=0)
This, also, is responsible for the validator value of ‘price’.
According to the docs, it seems that there’s no way to put something like a database constraint on a field. The best you can do is add model “validators” which will be called if you call model validation or use a ModelForm
. The validators are skipped if you simply put values into an object and save()
.
So, you can add validation on the forms or you can add validation to the model which also get run on the form level if you use ModelForm
.
From the docs on “How validators are run”:
See the form validation for more information on how validators are run
in forms, and Validating objects for how they’re run in models. Note
that validators will not be run automatically when you save a model,
but if you are using aModelForm
, it will run your validators on any
fields that are included in your form. See the ModelForm documentation
for information on how model validation interacts with forms.
In Django 2.2 you can add constraints to a model which will be applied in the migrations as a constraint on the database table:
from decimal import Decimal
from django.db import models
class Item(models.Model):
price = models.DecimalField( _(u'Price'), decimal_places=2, max_digits=12 )
class Meta:
constraints = [
models.CheckConstraint(check=models.Q(price__gt=Decimal('0')), name='price_gt_0'),
]
Validation of Constraints
In general constraints are not checked during
full_clean()
, and do not raiseValidationErrors
. Rather you’ll get a database integrity error onsave()
.
Assuming this is your product model, and you want to add non-negative constraint on price field. You can add the meta constraint on the model:
class Product(models.Model):
price = models.DecimalField(max_digits=13, decimal_places=2)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
managed = True
db_table = 'product'
constraints = [
models.CheckConstraint(check=models.Q(price__gte='0'), name='product_price_non_negative'),
]
- Import dependencies
from decimal import Decimal
from django.core.validators import MinValueValidator
- Add validators
price = models.DecimalField(
decimal_places=2,
max_digits=12,
validators=[MinValueValidator(Decimal('0.01'))]
)