How to limit the maximum value of a numeric field in a Django model?

Django has various numeric fields available for use in models, e.g. DecimalField and PositiveIntegerField. Although the former can be restricted to the number of decimal places stored and the overall number of characters stored, is there any way to restrict it to storing only numbers within a certain range, e.g. 0.0-5.0 ?

Failing that, is there any way to restrict a PositiveIntegerField to only store, for instance, numbers up to 50?

Update: now that Bug 6845 has been closed, this StackOverflow question may be moot. – sampablokuper

django models IntegerFields limits not working

I’m trying to limit the possible values of an IntegerField in my Django model. I have read through this : How to limit the maximum value of a numeric field in a Django model? …and this : Set Django

How to set Value of One field of Django model equal to Other field of other Django model

Hi i am Setting the value of one field of my Django model equal to value of other field of Other model. This value should change dynamically. This is my first model class MainModel(AbstractBaseUser,

django model set field default value from admin panel

models.py class MyModel(models.Model): maximum_limit = models.PositiveIntegerField(default=5) Here I set maximum_limit default value is 5. But I want to set a value which is also editable from admin

Limit a Django ManyToMany by field value

Given the following models, how can I limit the number of ManyToMany relationships that can be created to the value of count in the Key model? For example, if count is 2 then only 2 devices can us

How do I set default field value to value of other field in a Django model?

If I have the following model in django; class MyModel(models.Model): name = models.CharField(max_length=50) fullname = models.CharField(max_length=100,default=name) How do I make the fullname field

How to make a form field numeric only in Django

While using Django modelforms I have a Integer field which is numeric only. But in the browser it comes as a text field in which I can enter characters. I want to make this only numeric. How to do

Django: How to define a dynamic initial value on a ForeignKey Model Field

How can one define a dynamic initial value on a foreign key field? With the code: from django.db import models from django.conf import settings from django.contrib.sites.models import Site class Examp

Django model field, alternative value return if null?

Is there a way to return a different set value for a django model field if that field has a null value? I have users with profile images (image_url), for users who do not have one I’d like to return

Fix maximum character limit in text field

How can a fixed character limit be imposed on a text field in Cocos2d?

django model field limit choice from other model fields

Well Im doing a football application and I have a fixture or game model, what this does is gets two teams, and well it adds a time and stuff for the game to happen, but I also have FixtureRedCard and

Answers

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.

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…

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)

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: Although these only work when you’re using the model in a ModelForm, not if you’re using the model “on its own”, sigh.

from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator

size = models.IntegerField(validators=[MinValueValidator(0),
                                       MaxValueValidator(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:

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.