Skip to content
Advertisement

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

Advertisement

Answer

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…

Advertisement