146👍
You could also create a custom model field type – see http://docs.djangoproject.com/en/dev/howto/custom-model-fields/#howto-custom-model-fields
In this case, you could ‘inherit’ from the built-in IntegerField and override its validation logic.
The more I think about this, I realize how useful this would be for many Django apps. Perhaps a IntegerRangeField type could be submitted as a patch for the Django devs to consider adding to trunk.
This is working for me:
from django.db import models
class IntegerRangeField(models.IntegerField):
def __init__(self, verbose_name=None, name=None, min_value=None, max_value=None, **kwargs):
self.min_value, self.max_value = min_value, max_value
models.IntegerField.__init__(self, verbose_name, name, **kwargs)
def formfield(self, **kwargs):
defaults = {'min_value': self.min_value, 'max_value':self.max_value}
defaults.update(kwargs)
return super(IntegerRangeField, self).formfield(**defaults)
Then in your model class, you would use it like this (field being the module where you put the above code):
size = fields.IntegerRangeField(min_value=1, max_value=50)
OR for a range of negative and positive (like an oscillator range):
size = fields.IntegerRangeField(min_value=-100, max_value=100)
What would be really cool is if it could be called with the range operator like this:
size = fields.IntegerRangeField(range(1, 50))
But, that would require a lot more code since since you can specify a ‘skip’ parameter – range(1, 50, 2) – Interesting idea though…
502👍
You can use Django’s built-in validators—
from django.db.models import IntegerField, Model
from django.core.validators import MaxValueValidator, MinValueValidator
class CoolModelBro(Model):
limited_integer_field = IntegerField(
default=1,
validators=[
MaxValueValidator(100),
MinValueValidator(1)
]
)
Edit: When working directly with the model, make sure to call the model full_clean method before saving the model in order to trigger the validators. This is not required when using ModelForm
since the forms will do that automatically.
- [Django]-ModuleNotFoundError: No module named 'grp' on windows
- [Django]-How do I clone a Django model instance object and save it to the database?
- [Django]-What does 'many = True' do in Django Rest FrameWork?
106👍
from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator
size = models.IntegerField(validators=[MinValueValidator(0),
MaxValueValidator(5)])
- [Django]-What is pip install -q -e . for in this Travis-CI build tutorial?
- [Django]-Django: Fat models and skinny controllers?
- [Django]-Creating email templates with Django
57👍
I had this very same problem; here was my solution:
SCORE_CHOICES = zip( range(1,n), range(1,n) )
score = models.IntegerField(choices=SCORE_CHOICES, blank=True)
- [Django]-Django aggregate or annotate
- [Django]-Django – How to pass several arguments to the url template tag
- [Django]-Django edit user profile
10👍
There are two ways to do this. One is to use form validation to never let any number over 50 be entered by a user. Form validation docs.
If there is no user involved in the process, or you’re not using a form to enter data, then you’ll have to override the model’s save
method to throw an exception or limit the data going into the field.
- [Django]-Disable session creation in Django
- [Django]-How to merge consecutive database migrations in django 1.9+?
- [Django]-Django – Render the <label> of a single form field
5👍
Here is the best solution if you want some extra flexibility and don’t want to change your model field. Just add this custom validator:
#Imports
from django.core.exceptions import ValidationError
class validate_range_or_null(object):
compare = lambda self, a, b, c: a > c or a < b
clean = lambda self, x: x
message = ('Ensure this value is between %(limit_min)s and %(limit_max)s (it is %(show_value)s).')
code = 'limit_value'
def __init__(self, limit_min, limit_max):
self.limit_min = limit_min
self.limit_max = limit_max
def __call__(self, value):
cleaned = self.clean(value)
params = {'limit_min': self.limit_min, 'limit_max': self.limit_max, 'show_value': cleaned}
if value: # make it optional, remove it to make required, or make required on the model
if self.compare(cleaned, self.limit_min, self.limit_max):
raise ValidationError(self.message, code=self.code, params=params)
And it can be used as such:
class YourModel(models.Model):
....
no_dependents = models.PositiveSmallIntegerField("How many dependants?", blank=True, null=True, default=0, validators=[validate_range_or_null(1,100)])
The two parameters are max and min, and it allows nulls. You can customize the validator if you like by getting rid of the marked if statement or change your field to be blank=False, null=False in the model. That will of course require a migration.
Note: I had to add the validator because Django does not validate the range on PositiveSmallIntegerField, instead it creates a smallint (in postgres) for this field and you get a DB error if the numeric specified is out of range.
Hope this helps 🙂 More on Validators in Django.
PS. I based my answer on BaseValidator in django.core.validators, but everything is different except for the code.
- [Django]-How can I handle Exceptions raised by dango-social-auth?
- [Django]-Django: Get list of model fields?
- [Django]-Pylint "unresolved import" error in Visual Studio Code
0👍
In the forms.py
Class FloatForm(forms.ModelForm):
class Meta:
model = Float
fields = ('name','country', 'city', 'point', 'year')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['point'] = forms.FloatField(max_value=100, min_value=1)
- [Django]-In a Django form, how do I make a field readonly (or disabled) so that it cannot be edited?
- [Django]-Python Django Gmail SMTP setup
- [Django]-Timestamp fields in django
0👍
It is worth mentioning that sometimes Django validation doesn’t work as Django validation is mostly an application-level validation, not validation at the database level. Also, Model validation is not run automatically on the save/create/update of the model. If you want to validate your values instantly in your code then you need to do it manually — using the override save()
method:
class UserRating():
SCORE_CHOICES = (
(1, _("Terrible")),
(2, _("Poor")),
(3, _("Average")),
(4, _("Very Good")),
(5, _("Excellent")),
)
score = models.PositiveSmallIntegerField(
choices=SCORE_CHOICES, default=1,
validators=[
MaxValueValidator(5),
MinValueValidator(1)
]
)
def save(self, *args, **kwargs):
if int(self.score) < 1 or int(self.score) > 5:
raise ValidationError('Score must be located between 0 to 5')
super(UserRating, self).save(*args, **kwargs)
...
- [Django]-Disable session creation in Django
- [Django]-Get list item dynamically in django templates
- [Django]-Django template includes slow?
0👍
Add validator like this your model column in models.py
class Planogram(models.Model):
camera = models.ForeignKey(Camera, on_delete=models.CASCADE)
xtl = models.DecimalField(decimal_places=10, max_digits=11,validators=[MaxValueValidator(1),MinValueValidator(0)])
if you are using create function to create objects change it to constructor like below….
and call fullclean() on that object and then save..
everything will work perfectly.
planogram = Planogram(camera_id = camera,xtl=xtl,ytl=ytl,xbr=xbr,ybr=ybr,product_id=product_id)
planogram.full_clean()
planogram.save()
- [Django]-Celery discover tasks in files with other filenames
- [Django]-Django models: default value for column
- [Django]-Does django with mongodb make migrations a thing of the past?
0👍
For example, you can use MaxValueValidator() and MinValueValidator() for models.DecimalField() and models.PositiveIntegerField() to set the available range of the value as shown below:
# "models.py"
from django.db import models
from django.core.validators import MaxValueValidator, MinValueValidator
class Test(models.Model):
num1 = models.DecimalField(
max_digits=3,
decimal_places=1,
validators=[
MaxValueValidator(10.0),
MinValueValidator(0.0)
],
)
num2 = models.PositiveIntegerField(
validators=[
MaxValueValidator(10),
MinValueValidator(0)
],
)
Finally, you better override num1
and num2
fields with forms.DecimalField() and forms.IntegerField() to set the available range of the value in Django Admin as shown below:
from django.contrib import admin
from .models import Test
from django import forms
class TestForm(forms.ModelForm):
num1 = forms.DecimalField(
max_value=10.0, min_value=0.0, step_size=0.1
)
num2 = forms.IntegerField(
max_value=10, min_value=0
)
@admin.register(Test)
class TestAdmin(admin.ModelAdmin):
form = TestForm
In addition, the code with forms.NumberInput below is identical to the code above:
from django.contrib import admin
from .models import Test
from django import forms
class TestForm(forms.ModelForm):
num1 = forms.DecimalField(
widget=forms.NumberInput(attrs={'max': 10.0, 'min': 0.0, 'step': 0.1})
)
num2 = forms.IntegerField(
widget=forms.NumberInput(attrs={'max': 10, 'min': 0})
)
@admin.register(Test)
class TestAdmin(admin.ModelAdmin):
form = TestForm
- [Django]-Add additional options to Django form select widget
- [Django]-Nginx doesn't serve static
- [Django]-Proper way to handle multiple forms on one page in Django